1. useRef(保存引用值)
useRef
通常用于保存“不会参与 UI 渲染,但生命周期要长”的对象引用,比如获取 DOM、保存定时器 ID、WebSocket等。
新建useRef.js
组件,写入代码:
import React, { useRef, useState } from 'react'
export default function UseRef() {
const name = useRef<HTMLInputElement>(null)
let [list, setList] = useState(['000', '111', '222'])
let btnHandle = () => {
if (name.current) {
setList([...list, name.current.value])
name.current.value = ''
}
}
let delHandle = (index: number) => {
let temList = [...list]
temList.splice(index, 1)
setList(temList)
}
return (
<div>
<input ref={name} />
<button onClick={btnHandle}>click</button>
<ul>
{list.map((value, index) => {
return (
<li key={index}>
{value}
<button onClick={() => delHandle(index)}>删除</button>
</li>
)
})}
</ul>
</div>
)
}
上面的name会保存引用值,可以带入到点击事件,效果:
不仅如此,useRef
还能在函数组件中保持状态:
import React, { useState, useRef } from 'react'
export default function UseRef() {
const [count, setCount] = useState(0)
let myCount = useRef(0)
const addHandle = () => {
setCount(count + 1)
myCount.current++
}
return (
<div>
<button onClick={addHandle}>click</button>
{count} - {myCount.current}
</div>
)
}
上面的myCount当值变化时,能够实时保存。
2. useCallback(记忆函数)
防止因为组件重新渲染,导致方法被重新创建,起到缓存作用,只有第二个参数变化了,才重新声明一次。
新建 UseCallback.js
方法组件,写入代码:
import React, { useCallback, useEffect } from 'react'
export default function UseCallback() {
const [userId, setUserId] = useState(1)
const [user, setUser] = useState<any>(null)
const [counter, setCounter] = useState(0)
const fetchUser = useCallback(() => {
console.log(`Fetching user with ID ${userId}...`)
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data))
}, [userId])
useEffect(() => {
fetchUser()
}, [fetchUser])
return (
<div>
<h2>用户信息</h2>
{user ? (
<div>
<p>名字: {user.name}</p>
<p>邮箱: {user.email}</p>
</div>
) : (
<p>加载中...</p>
)}
<button onClick={() => setUserId(id => id + 1)}>切换用户</button>
<button onClick={() => setCounter(c => c + 1)}>其他按钮(不影响 fetch)</button>
<p>Counter: {counter}</p>
</div>
)
}
export default UseCallback
上面仅当 userId 变化时,fetchUser 函数才会变化,userId 不变就不重新生成函数。效果:
如果不使用 useCallback
,每次渲染时函数都会创建,这在传给子组件或放到 useEffect
/ onClick
等地方时,会带来性能浪费、重复渲染、无法复用的问题。
3. useMemo(记忆组件)
useMemo
是 值级缓存,用于缓存变量、数组、对象、计算结果,不同于 useCallback
是 函数级缓存。
import React, { useState, useMemo } from 'react'
const UserList = () => {
const [query, setQuery] = useState('')
const [users] = useState([
'Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'George'
])
const filteredUsers = useMemo(() => {
console.log('Filtering...')
return users.filter(user => user.toLowerCase().includes(query.toLowerCase()))
}, [query, users])
return (
<div>
<input
placeholder="搜索用户"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<ul>
{filteredUsers.map((user, index) => (
<li key={index}>{user}</li>
))}
</ul>
</div>
)
}
export default UserList
结果:
上面只有当 query 或 users 变化时,才重新过滤;如果不使用 useMemo,
每次组件渲染时,users.filter(...)
都会执行一次,即使输入没有变。