第十一章 React的Effect(React18源码解析十一)

151 阅读3分钟

第一章 JSX(React18源码解析一)
第二章 实现Virtual DOM(React18源码解析二)
第三章 根节点关联根Fiber(React18源码解析三)
第四章 初始化UpdateQueue、添加update(React18源码解析四)
第五章 实现时间切片函数和拷贝Fiber(React18源码解析五)
第六章 构建FiberTree(React18源码解析六)
第七章 commit(React18源码解析七)
第八章 React中的事件(React18源码解析八)
第九章 useReducer、useState(React18源码解析九)
第十章 React的dom diff(React18源码解析十)
第十一章 React的Effect(React18源码解析十一)
第十二章 React的同步、并发渲染(React18源码解析十二)
第十三章 React高优打断低优、饥饿问题(React18源码解析十三)

useEffect和useLayoutEffout的区别

二者都用来给Function Component添加副作用,区别1.是执行时机的不同,useLayoutEffect是在DOM更新完成,浏览器渲染之前执行,useEffect是在浏览器渲染之后执行 2.useLayoutEffect是在DOM更新后同步执行阻塞浏览器渲染,useEffect不会阻赛浏览器渲染

useEffect\useLayoutEffect的mount阶段

function component fiber添加flags,
useEffect是Passive,useLayoutEffect是Update,
为后面判断function component上是否有effect hooks做准备,
创建effect hook添加到fiber.memoizedState上的hooks链表上,
useEffect(create function,deps)会在内部转成结构如下:
//effect:
{
    tag:"effect标识及那种effect",
    create:"useEffect传递过来的create function",
    destroy:"useEffect传递过来的create function返回的destroy",
    deps:"useEffect传递过来的deps",
    next: "下一个effect",
}
添加到fiber.updateQueue.lastEffect链上,
同时effect hook.memoizedState指向此effect,
effect hooks会在fiber.updateQueue.lastEffect新建一条循环链表专门用于存effect hooks,
在effect.tag上标识出effect类型,
useEffect是HasEffectPassive,useLayoutEffect是HasEffectLayout,
后面create、destroy的执行及用effect.tag判断

useEffect\useLayoutEffect的update阶段

根据old effect hook创建new effect hook,
并添加到new fiber.memoizedState新的hooks链表上,
同时根据重新调用useEffect(create function,deps)传递过来的create function、deps创建new effect,
并赋给new effect hook.memoizedState,
并添加到new fiber.updateQueue.lastEffect循环链表上,
同时会比较old effect deps和新传递过来的deps,若两者相同,会删除effect.tagHasEffect,
为后面create、destroy的执行判断提供依据,

useEffect的执行

会在coomit阶段开一个scheduler执行effects,
因scheduler是一个宏任务所以useEffect的执行会在渲染之后且不会阻赛渲染,
先执行unmount及执行destroy,
从root fiber递归向下,到达底部后再递归向上,
从fiber.updateQueue.lastEffect上取的所有effect,
判断effect.tag是否等于HasEffectPassive,
等于则从effect.destroy取的destroy函数执行,
遍历完effects后执行mount及create function,
同unmount一般,
从root fiber递归向下,到达底部后再递归向上,
从fiber.updateQueue.lastEffect上取的所有effect,
判断effect.tag是否等于HasEffectPassive,
等于则从effect.create取的create函数执行,

useLayoutEffect的执行

在每一个function component fiberDOM更新完成后同步执行该fiber上的useLayoutEffect effects,
从fiber.updateQueue.lastEffect上取的所有effect,
判断effect.tag是否等于HasEffectLayout,
等于则从effect.destroy取的destroy函数执行,

在所有DOM更新后同步执行useLayoutEffects的mount及create function,
从root fiber递归向下,到达底部后再递归向上,
从fiber.updateQueue.lastEffect上取的所有effect,
判断effect.tag是否等于HasEffectLayout,
等于则从effect.create取的create函数执行,