React Diff 算法源码阅读笔记

技术 2月 17, 2021

本文内容基于 React 17.0.0,主要在 legacy mode 下针对 React-reconciler 来进行分析

导读

React Diff 的过程发生在 beginWork 内,每个节点被 Diff 的时机基本上都是在其父节点状态更新快结束后发生的,其关键函数是一个叫 reconcileChildren 的函数。所以下文均会使用 reconcileChildren 来代指 Diff 的发生。

reconcileChildren 不会直接涉及子节点的状态更新,只是 创建新 Fiber、复用旧 Fiber 、找到需要删除的无用旧 Fiber,然后生成一个得到一个最新状态的第一个子节点的 Fiber,然后在下一个 workLoop 中进行更细节的节点状态更新等。

ReconcileChildren

源码:https://github.com/facebook/react/blob/v17.0.0/packages/react-reconciler/src/ReactChildFiber.old.js#L1274

函数签名

function reconcileChildFibers(
	returnFiber: Fiber, // WIP 的 Fiber 节点
	currentFirstChild: Fiber | null, // Current 节点的第一个子节点的 Fiber
	newChild: any, // 最新的子节点的 ReactElement
	lanes: Lanes, // 更新优先级,在本文中无需在意
): Fiber | null {}

逻辑流程图

image.png

小节

ReconcileChildren 主要会通过新的子节点的 ReactElement 类型来将逻辑分流,分别到其他自逻辑进行详细的 Diff,下面会进行一一的罗列。

reconcileSingleElement

源码:https://github.com/facebook/react/blob/v17.0.0/packages/react-reconciler/src/ReactChildFiber.old.js#L1135

image.png

reconcileSinglePortal

源码:https://github.com/facebook/react/blob/v17.0.0/packages/react-reconciler/src/ReactChildFiber.old.js#L1235

image.png

reconcileSingleTextNode

源码:https://github.com/facebook/react/blob/v17.0.0/packages/react-reconciler/src/ReactChildFiber.old.js#L1111

image.png

reconcileChildrenArray

源码:https://github.com/facebook/react/blob/v17.0.0/packages/react-reconciler/src/ReactChildFiber.old.js#L771

image.png

reconcileChildrenIterator

源码:https://github.com/facebook/react/blob/v17.0.0/packages/react-reconciler/src/ReactChildFiber.old.js#L926

迭代器的 reconciler 方式与 reconcileChildrenArray 基本一致,只不过遍历方式等做了一些区分,便不再赘述了。

Pengsha Ying

逝者如斯,故不舍昼夜