由于stack reconciler中存在任务打断实现成本过高等问题,React从16版本开始,把fiber reconclier 变成了默认的 reconciler,需要注意的时,此时并没有开启并发模式,但是从React 18开始(ReactDom.createRoot(DomElment)
),默认开启current mode(更多细节查看:React 18介绍)
Fiber reconciler解决的问题
- 能够把可中断的任务切片处理。
- 能够调整优先级,重置并复用任务。
- 能够在父元素与子元素之间交错处理,以支持 React 中的布局。
- 能够在
render()
中返回多个元素。
- 更好地支持错误边界。
你可以在这里和这里,深入了解 React Fiber 架构。虽然这已经在 React 16 中启用了,但是 async 特性还没有默认开启。
源代码在 packages/react-reconciler
目录下
两个阶段:render和commit
render
阶段,React将更新应用于调用setState
或props changed
的组件,React.render
会找出需要在UI中进行更新的内容。如果是初始渲染,React将为render
方法返回的每个元素(react element) 创建一个新的Fiber节点。在下次更新中,将复用和更新现有React元素的Fiber Node。该阶段的会基于current tree 生成是一棵带有副作用的Fiber Node树,也就是俗称的WIP树(working in progerss tree)。 WIP树描述了下一阶段,commit
阶段需要完成的工作(通过Flags、subTreeFlags字段,更多字段说明)。
commit
阶段,React会基于WIP树,递归遍历,按照顶层到底部的顺序,并执行DOM Mutation和用户可见的其他更改。
备注:
React 18的源码中,已经没有Effect List相关的代码逻辑,会全全解遍历,根据*Flags标识判断当前节点或其节点的操作
--------------------------------------分割线--------------------------------------
需要着重了解的是render
阶段的工作是可以异步、中断、重置执行。
--------------------------------------分割线--------------------------------------
React可以根据可用时间来处理一个或多个fiber node,可以停止存储已完成的工作并去执行其它高优时间,执行后会从中断处继续(通过修改WIP当前指向的节点来实现)。但是有时候,它可能需要放弃所做的工作,然后从头开始重新执行。由于在此阶段执行的工作不会导致任何用户可见的更改(例如DOM更新),因此可以随时暂停。相反,下一个commit
阶段始终是同步的。这是因为在此阶段执行的工作会导致用户可见的更改,例如DOM更新。这就是为什么React需要一次完成它们的原因。
render阶段调用生命周期函数
调用生命周期方法是React进行的一种工作。在此render
阶段将调用某些方法,而在此阶段将调用其他方法commit
。这是在第一render
阶段工作时调用的生命周期的列表:
- [UNSAFE_] componentWillMount(已弃用)
- [UNSAFE_] componentWillReceiveProps(已弃用)
- getDerivedStateFromProps
- shouldComponentUpdate
- [UNSAFE_] componentWillUpdate(不建议使用)
- render
如你所见,该render
阶段中执行的某些旧式生命周期方法被标记为UNSAFE
版本16.3中的版本。它们现在在文档中称为旧版生命周期。它们将在以后的16.x发行版中弃用,而没有UNSAFE
前缀的对应版本将在17.0中删除。您可以在此处阅读有关这些更改和建议的迁移路径的更多信息。
为什么这些生命周期函数会被弃用?
我们刚刚了解到,由于该render
阶段不会产生像DOM更新这样的副作用,因此React可以异步地处理组件的更新(甚至可能在多个线程中进行)。但是,标UNSAFE
有的生命周期经常被误解和巧妙地滥用。开发人员倾向于将带有副作用的代码放入这些方法中,这可能会导致新的异步呈现方法出现问题。尽管只会删除没有UNSAFE
前缀的声明周期方法,但它们仍可能在即将出现的并发模式(您可以选择退出)中引起问题。
commit阶段调用生命周期函数
以下是在commit
阶段执行的生命周期方法的列表:
- getSnapshotBeforeUpdate
- componentDidMount
- componentDidUpdate
- componentWillUnmount
因为这些方法在同步commit
阶段执行,所以它们可能包含副作用并涉及DOM。
参考文章: Inside Fiber: an in-depth overview of the new reconciliation algorithm in React