useCallback
1.如果先点击id为count的div,再点击id为fun的div,会打印什么?
const [count, setCount] = useState(0)
const fun=useCallback(()=>{
console.log(count,'count')
},[])
return (
<>
<div id='count' onClick={() => setCount(count + 1)}>{count}</div>
<div id='fun' onClick={fun}>{count}</div>
</>
)
结果:0
相信很多人都可以答对,因为useCallback就是用来缓存函数的,他会在第二个参数数组中依赖项的值发生改变时才会重新返回新的函数,代码中我没有给依赖项,所以这个函数是不会重新返回新的函数,所以里面的打印会一直打印初始值,但是如果第二个参数写入依赖项count,那么就会一直打印最新值了,因为每次count改变,都会返回最新的函数,所以里面的值也是最新的
2.项目中怎么使用?
//父组件
function App() {
console.log('app加载啦~')
const [count, setCount] = useState(0)
const fun=useCallback((num)=>{
console.log('fun触发啦~')
console.log(num)
},[])
return (
<>
<div id='count' onClick={() => setCount(count + 1)}>{count}</div>
<Son fun={fun}></Son>
</>
)
}
//子组件
const Son=memo(({fun})=>{
console.log('son加载啦~')
return (
<>
<button onClick={()=>fun(2)}>触发父组件的方法</button>
</>
)
})
项目中有在父组件传一个函数给子组件,子组件如果渲染特别耗时,可以使用useCallback来缓存函数后传入子组件,这样除非依赖项发生改变,那么每次传入子组件的都是一个相同函数,再配合memo(包裹组件,除非组件传入的props发生改变,不然组件不会渲染)这样就会让子组件除非useCallback的依赖项发生改变不然不会重新渲染了~
useMemo
1.点击id为count的div,子组件会重新渲染嘛?
//父组件
function App() {
console.log('app加载啦~')
const [count, setCount] = useState(0)
const [num, setNum] = useState(10)
const items=useMemo(()=>{
const arr=[]
for (let i = 0; i < num; i++) {
arr.push(i)
}
return arr
},[num])
return (
<>
<div id='count' onClick={() => setCount(count + 1)}>{count}</div>
<Son items={items}></Son>
</>
)
}
//子组件
const Son=memo(({items})=>{
console.log('son加载啦~')
return (
<>
{
items.map(item=><div>{items}</div>)
}
</>
)
})
结果:不会
因为依赖项num没有发生改变,那么useMemo还是会返回之前缓存的结果,所以items是没变的,子组件也不会重新渲染
结论
1.两者都可以配合memo来进行性能优化,不过区别是,useCallback缓存的是函数体,useMemo缓存的是结果,个人感觉useMemo可以理解为Vue中的computed,都是依赖项发生改变时才重新计算返回值