跳到主要内容

认识

2023年12月28日
柏拉文
越努力,越幸运

一、认识


<Suspense> 允许在子组件完成加载前展示后备方案。<Suspense> 可以与以下组合使用:

  1. lazy 组件

  2. transition fallback

  3. use

  4. Offscreen

  5. Selective Hydration

  6. RSC

1.1 架构

Suspense 架构:

  • 正常状态: <Suspense> 渲染子孙组件

  • 挂起状态: <Suspense> 渲染 fallback

其中, 造成挂起状态的原因有很多, 比如:

  • <Cpn /> 或者子孙组件是懒加载组件

  • <Cpn /> 或者子孙组件触发并发更新

  • <Cpn /> 或者子孙是 Selective Hydration

  • <Cpn /> 或者子孙组件使用 use 请求数据

1.2 思想

Suspense 的实现有两种思路:

  • 只有一个 Child: Pending 流程 child 指向 fallback, 正常流程指向 children。这样的实现有两个缺点:

    • 无法保存 children 对应状态

    • 切换后 children 对应 DOM 需要完全销毁

  • 有两个 Child: beginWork 时, Suspense.child 始终指向 Offscreen 对应 children, Suspense.child.sibling 指向 Fragment 对应 fallback。通过改变 Offscreenmode 值来改变显示与隐藏, Offscreen 子树不会解除绑定, Offscreen 中的状态得以保留。因此, React 采用的是这种思路。

二、工作流程


Suspense 工作流程如下:

  1. beginWork 时进入以下任意流程:

    1. mount 时正常流程

    2. update 时正常流程

    3. mount 时挂起流程

    4. update 时挂起流程

  2. completeWork 时对比 current Offscreen modeworkInProgress Offscreen mode, 如果发现下述情况, 则标记 Visibility EffectTag:

    • modehidden 变为 visible

    • modevisible 变为 hidden

    • current === null && hidden

  3. commitWork 时处理 Visibility EffectTag, 处理 Visibility EffectTag时需要找到所有子树顶层 Host 节点

三、触发流程


3.1 use

  1. 正常流程对应 render 阶段

  2. 遇到 use, use 手动抛出 SuspenseException 错误, 进入 Suspense 挂起流程

  3. 进入 Suspense 挂起流程对应 render 阶段

  4. 进入 Suspense 挂起流程 commit 阶段,渲染 fallback 对应的 Loading 组件

  5. 请求返回后,进入正常流程对应的 render 阶段

  6. 进入正常流程对应的 commit 阶段, 渲染 Suspense 对应的 Children