// Flip isDehydrated to false to indicate that when this render
// finishes, the root will no longer be dehydrated.
const overrideState: RootState = {
element: nextChildren,
isDehydrated: false,
cache: nextState.cache,
transitions: nextState.transitions,
};
const updateQueue: UpdateQueue<RootState> = (workInProgress.updateQueue: any);
// `baseState` can always be the last state because the root doesn't
// have reducer functions so it doesn't need rebasing.
updateQueue.baseState = overrideState;
workInProgress.memoizedState = overrideState;
以及调用 enterHydrationState 函数:获取第一个 DOM 节点并赋值全局变量 nextHydratableInstance。
快速预览
react hydrate 是指,在 SSR 模式下渲染出 html 字符串发送到浏览器渲染之后,绑定监听事件以及将 react Fiber 树构建出来的过程,也就是所谓的「水合」,或者叫做「注水」。
一个简单的例子🌰
大致过程:通过
renderToString
等方法,将 React 组件代码处理成 HTML(Fiber 树 => HTML,去掉所有绑定事件,只留 HTML 信息),返回浏览器或者搜索引擎,实现 SSR 的效果。客户端 React 也不需要再一次处理 DOM 元素,只需要绑定的事件,处理 Fiber 树等即可。一举两得。重点就在下面的代码里面,调用 hydrateRoot 时第二个参数,也就是把 React 组件重新「执行」一下。这里的 React 组件要和服务端 SSR 时放入的组件一致。
下面进入代码分析阶段,回答 2 个问题:
事件什么时候绑定
hydrateRoot
函数内部会调用listenToAllSupportedEvents(container)
,这里的 container 就是 DOM 容器节点 。listenToAllSupportedEvents
函数就是处理委托事件的开始入口,具体实现可以看这篇文章。Fiber 树构建
承接上段,
hydrateRoot
函数内部会执行如下创建逻辑,进入 Fiber 树构造。最大的区别在于,跳过 DOM 树的创建和增加。createHydrationContainer
(createFiberRoot: FiberRootNode, createHostRootFiber)createFiberRoot
的第 3 个参数被赋值为 true,最终影响该数据结构scheduleInitialHydrationOnRoot
,和scheduleUpdateOnFiber
相比,代码更加简单,标记 lanes,就直接进入ensureRootIsScheduled
阶段以优先级 16 开启更新
开始更新时,使用默认优先级 16,React18 版本下会进入并发,但不会分片。(16 是在 BlockingLane 范围内)
Render 阶段
updateHostRoot
在 render 阶段的 beginWork 阶段处理 HostRoot 的 updateHostRoot 函数内会对 isDehydrated 判断。如果是真值,会更新 updateQueue.baseState 和 workInProgress.memoizedState
以及调用
enterHydrationState
函数:获取第一个 DOM 节点并赋值全局变量nextHydratableInstance
。updateHostComponent
在 render 阶段的 beginWork 阶段处理 HostComponent 的 updateHostComponent 函数,会将已经存在的 DOM 实例和子 fiber 进行关联,也就是赋值 fiber.stateNode,通过
tryToClaimNextHydratableInstance
完成,tryHydrate
函数完成具体的赋值 stateNode 操作。在 render 阶段的 completeOfWork 内处理 HostComponent 分支时,下面的语句返回真值,进入「水合」处理,判断当前节点是否存在更新
Commit 阶段
HostRoot
根据 HostRoot 的
memoizedState.isDehydrated
为 true,会进入commitHydratedContainer
逻辑,该逻辑会处理 queuedDiscreteEvents。后续
处理所有副作用和生命周期,和正常的 Commit 阶段类似,不再赘述。
以上