看下下面这段代码,点击后会打印什么内容
const Mytest = () => {
const [state, setState] = useState({
a: 1
})
useEffect(() => {
setState({
a: 4
})
}, []);
const handleClick = useCallback(() => {
console.log(state)
}, [ ]);
return (
<div onClick={handleClick}>
click me
</div>)
};
export default Mytest;
触发handleClick,打印出来的值为:
{ a: 1 }
为什么呢?
明明useEffect发生在组件挂载完了之后才执行的,触发handleClick的时候,按理说state已经更新了,
但为什么还是拿到了没有更新之前的值呢?
原因就出在useCallback, useback对函数做了一次缓存,如果它的依赖是个空数组,就只会在第一次渲染的时候生成一个handleClick函数引用,后面的每次都渲染都复用之前的函数,并且用useCallback包住的函数,已经形成了一个闭包,闭包内用了外部的变量, 在函数执行完后,并没有销毁这个变量, 所以再次调用这个函数的时候, 还是用的之前的变量
如果把函数handleClick改成如下,以来
const handleClick = useCallback(() => {
console.log(state)
}, [state ]);
{ a: 4 }
这时候,state有更新的时候,就会重新执行这个useCallback, 返回一个新的函数引用, 这样就能拿到最新的state了
function Parent(){
const [query,setQuery] = useState('q');
const fetchData = useCallback(()=>{
...省略函数体的具体实现
},[query]);
return <Child fetchData={fetchData} />
}
function Child({fetchData}){
const [data,setData] = useState(null);
useEffect(()=>{
fetchData().then(setData);
},[fetchData])
经过 useCallback 包装过的函数可以当作普通变量作为 useEffect 的依赖。 useCallback做的事情,就是在其依赖变化时,返回一个新的函数引用,触发 useEffect 的依赖变化,并激活其重新执行