关于React源码学习(草稿)

关于React源码学习(草稿)

十一月 21, 2020

最近尝试学习React的源码,学习阶段,先建个草稿,记录片段。

正文

个人觉得,React很多处代码都是异步执行的,不能像其他仓库一样从入口文件开始调试。学习React源码则得从好几个入口切入。

阶段

React更新时会分为两个阶段render阶段与commit阶段

render阶段

在render阶段,React将更新应用于通过setState或render方法触发的组件,并确定需要在用户屏幕上做哪些更新–哪些节点需要插入,更新或删除,哪些组件需要调用其生命周期方法。最终的这些更新信息被保存在一个叫effect list的fiber 节点树上。当然,在首次渲染时,React不需要产生任何更新信息,而是会给每个从render方法返回的element生成一个fiber节点,最终生成一个fiber节点树, 后续的更新也是复用了这棵fiber树。

render阶段被标记为纯的、没有副作用的,可能会被React暂停、终止或者重新执行。也就是说,React会根据产生的任务的优先级,安排任务的调度(schedule)。利用类似requestIdleCallback的原理在浏览器空闲阶段进行更新计算,而不会阻塞动画,事件等的执行。

render阶段开始与beginWork,终止与completeWork

commit阶段

在这个阶段时,React内部会有三个fiber树:

1
2
3
4
5
6
current fiber tree: 在首次渲染时,React不需要产生任何更新信息,而是会给每个从render方法返回的element生成一个fiber节点,最终生成一个fiber节点树, 后续的更新也是复用了这棵fiber树。

workInProgress fiber tree:
所有的更新计算工作都在workInProgress tree的fiber上执行。当React 遍历current fiber tree时,它为每个current fiber 创建一个替代(alternate)节点,这样的alternate节点构成了workInProgress tree

effect list fiber tree: workInProgress fiber tree 的子树,这个树的作用串联了标记具有更新的节点

commit阶段会遍历effect list,把所有更新都commit到DOM树上。具体的,首先会有一个pre-commit阶段,主要是执行getSnapshotBeforeUpdate方法,可以获取当前DOM的快照(snap)。然后给需要卸载的组件执行componentWillUnmount方法。接着会把current fiber tree 替换为workInProgress fiber tree。最后执行DOM的插入、更新和删除,给更新的组件执行componentDidUpdate,给插入的组件执行componentDidMount。

重点要注意的是,这一阶段是同步执行的,不能中止。

commitRoot方法是commit阶段工作的起点

commit阶段的三个流程

before mutation阶段(执行DOM操作前)

mutation阶段(执行DOM操作)

layout阶段(执行DOM操作后)

React.createElement

ReactDOM.render

首次调用render,会给传入的container添加一个参数:_reactRootContainer。然后下面又有个:_internalRoot,这个对象包含着所谓的fiberRootNode,是整个应用的根节点。

fiberRootNode的current参数,存储着这个应用的fiber链表的第一个节点。

此时的fiber节点还是树状结构,也就是传说中的虚拟dom

fiber

Update

Hook

链接

React技术揭秘-卡颂