1.useCallback
用于得到一个固定引用值的函数,通常用它进行性能优化
useCallback:
该函数有两个参数:
- 函数,useCallback会固定该函数的引用,只要依赖项没有发生变化,则始终返回之前的函数地址
- 数组,记录依赖项
该函数的返回值:引用相对固定的函数地址
例1:
//伪代码
function TEXT(props) {
console.log('text render')
return (
<div>
{props.text}
<Button onClick={props.onClick} />
</div>
)
}
function Parent() {
const [txt, setTxt] = useState(123)
const [n, setN] = useState(0)
const handleClick = useCallback(() => {
set(txt + 1)
}, [txt])
const handleClick=()=>{
set(txt + 1)
}
// 注释1: const handleClick = useCallback(() => {
// set(txt + 1)
// }, [txt])
//注释2: const handleClick=useMemo(()=>{
// return ()=>{
// setText(txt+1)
// }
// },[txt])
return (
<div>
<Text text={txt} onClick={handleClick} />
<input type='number' value={n} onChange={() => {
setN(parseInt(e.target.value))
}} />
</div>
)
}
parent组件中引用了TEXT组件,父组件input 变化会触发父组件重新渲染;每次父组件重新渲染,都会使TEXT组件也重新渲染。
而使TEXT组件重新渲染的原因是,传入的props改变了,其中,text并没有变,而是每次Parent重新渲染时,都会重新创建一个handleClick函数,函数内容没有变,函数的地址变了,所以TEXT会重新渲染
解决方法:父组件触发input时,不要改变handleClick的地址就好了。useCallback正好有这个功能,如下注释1的代码:当依赖项没有改变时,则useCallback始终返回之前的函数地址。它返回一个函数,赋值给handleClick。对于TEXT组件来说,props的text没有变,传入函数(地址)也没有变。所以不会重新渲染
2.useMemo
用于保存一些比较稳定的数据,通常用于性能优化
如上例子如果用useMemo实现,见注释2。
useCallback返回的是函数,useMemo返回的是函数的执行结果,即上面代码中return 里面的内容,可以是函数、数组、对象。
例2:
父组件App,子组件Item,父组件中,有一个复杂计算,循环10000次,初始时会执行一次,后面每次input改变都会执行。
优化,使用如下注释代码,useMemo返回值为一个数组,只要range不变,则这个复杂的计算不需要重新执行,子组件也不需要重新渲染
function Item(props) {
<li>{props.value} </li>
}
function App() {
const [range,] = useState({ min: 1, max: 10000 })
const [n, setN] = useState(0)
const list = []
for (let i = range.min; i < range.max; i++) {
list.push(<Item key={i} value={i} />)
}
// const list = useMemo(() => {
// const list = []
// for (let i = range.min; i < range.max; i++) {
// list.push(<Item key={i} value={i} />)
// }
// return list
// }, [range.max,range.min])
return (
<div>
<ul>
{llist}
</ul>
<input type='number' value={n} onChange={e => {
setN(parseInt(e.target.value))
}} />
</div>
)
}
3.对比
共同点:
两者都用于缓存数据,性能优化;接收参数是一样的,第一个参数为回调函数,第二个表示以来的数据
区别:
useMemo :缓存的结果是回调函数中return的值,主要用于缓存计算结果的值,应用场景如需计算的状态。
useCallback:缓存的结果是函数,主要用于缓存函数。因为函数式组件每次任何一个state发生变化,会触发整个组件更新,一些函数是没有必要更新的,此时就应该缓存起来,提高性能,减少对资源的浪费