useEffect
语法: useEffect(setup, dependencies?)
含义: useEffect 是一个 React Hook,它允许你 将组件与外部系统同步。
useEffect 源码简单理解
一、mountEffect 和 upadateEffect
useEffect 与其它 hooks 一样分为 mountEffect 和 upadateEffect 两个阶段
第一次执行 mountEffect
后面执行 upadateEffect
从代码中可以看出 mountEffect 和 upadateEffect 传参都是 函数 和 依赖数组,调用 mountEffectImpl 和 updateEffectImpl。
mountEffectImpl 和 updateEffectImpl 它们的四个入参一样。其中前面两个入参表示 tag 实现了指定的行为,具体可参考源码 ReactSideEffectTags.js 和 ReactHookEffectTags.js文件,暂时忽略。
二、mountEffectImpl 和 updateEffectImpl
mountEffectImpl
以上代码中可以看出 执行 pushEffect 并将返回结果记录在 hook的memoizedState上
updateEffectImpl
以下代码可以看出 当 currentHook 为空的时候,updateEffectImpl 的逻辑与 mountEffectImpl 的逻辑是一样。当 currentHook 不为空、依赖数组不为空时,判断依赖数组里的值是否有变化,若相等无变化则执行pushEffect。猜测这个时候的 hookFlags 指不执行这次 useEffect。
不管哪个阶段最终都执行 pushEffect 函数,那它是啥呢?
pushEffect
这个函数首先根据入参声明了一个新的 effect 并返回。它实际是一个循环链表
Effect = {
tag: HookEffectTag, // 一个二进制数,它将决定 effect 的行为
create: () => (() => void) | void, // 绘制后应该运行的回调
inst: (() => void) | void, // 用于确定是否应销毁和重新创建 effect
deps: Array<mixed> | null, // 决定重绘制后是否执行的 deps
next: Effect, // 函数组件中定义的下一个 effect 的引用
};
componentUpdateQueue : 存储 Effect 的全局变量
判断 componentUpdateQueue 是否为空:
- componentUpdateQueue 空:与 mountEffect 逻辑类似,它会创建一个空的 componentUpdateQueue,它其实是 {lastEffect: null},之后将 componentUpdateQueue.lastEffect 指向 effect.next,其实就是存了一下 effect
- componentUpdateQueue 不为空:
2.1 lastEffect 为空:这种情况是新的渲染阶段的第一个 useEffect,逻辑处理和 componentUpdateQueue 为空时一致
2.2 lastEffect 不为空:这种情况意味着这个组件有多个 useEffect,是第二个及其之后的 useEffect 会走到的分支,将 lastEffect 指向下一个 effect
最后 returen effect
小结
以上就是 useEffect 源码的大致流程。表面上到这里就结束啦。
但不难发现,useEffect 的很多功能在上面代码并没有实现。还有以上代码中的 pushEffect 之后又有哪些逻辑呢?componentUpdateQueue 存储 Effect 之后会在哪里被用到?
饿了,先干饭去,后面接着总结。未完待续。。。