React学习笔记:调和器(Recociler)- Fiber reconclier

395 阅读4分钟

由于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 目录下

两个阶段:rendercommit

render阶段,React将更新应用于调用setStateprops 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