useEffect
useEffect 我认为是React开发过程中最需要深入理解的hooks,这有助于我们写出更干净的React代码; React官网链接会把useEffect列为逃生舱范围的api,并给出了大量使用useEffect的例子在React的思想中,一个干净的函数应该是输入和输出一致的,但是真实的开发并不是总能这样,所以需要这样的一个副作用函数来帮助我们解决一些额外的问题 在开发的过程中尽可能避免减少使用useEffect(这里网上也有很多文章讲), 只有不可避免的数据请求,事件监听 甚至dom操作才应该在useEffect中使用; 其他的一切应该通过函数式开发来完成,如果你发现一些操作不可避免的需要使用useEffect通常是架构设计出了问题;
现在我们来正式介绍useEffect
useEffect
本身可以看作一个闭包 并不会跟着组件更新而发生引用的变化 除非依赖发生改变;
如果你不理解 这里建议结合miniuseState源码和 Dan的文章结合来看。
每次组件渲染后 React 会先执行所有 useEffect 的清理函数(即 return 的函数,如果有的话),清理的是上一次渲染的副作用,然后才会执行本次渲染的 useEffect 回调函数。
useEffect(
// 其次执行
()=>{
// 渲染首先执行
return ()=>{}
},[])
从源码的角度来分析useEffect
初始化
function mountEffect(create,deps){
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
currentlyRenderingFiber.effectTag |= UpdateEffect | PassiveEffect;
hook.memoizedState = pushEffect(
HookHasEffect | hookEffectTag,
create, // useEffect 第一次参数,就是副作用函数
undefined,
nextDeps, // useEffect 第二次参数,deps
)
}
更新
function updateEffect(create,deps){
const hook = updateWorkInProgressHook();
if (areHookInputsEqual(nextDeps, prevDeps)) { /* 如果deps项没有发生变化,那么更新effect list就可以了,无须设置 HookHasEffect */
pushEffect(hookEffectTag, create, destroy, nextDeps);
return;
}
/* 如果deps依赖项发生改变,赋予 effectTag ,在commit节点,就会再次执行我们的effect */
currentlyRenderingFiber.effectTag |= fiberEffectTag
hook.memoizedState = pushEffect(HookHasEffect | hookEffectTag,create,destroy,nextDeps)
}
再推荐下我认为讲解useEffect使用最好的文章 dan的useEffect