主题
实现Suspense
第22课 实现Suspense
本节课代码地址(请参考课程获取) 本节课的目标:了解·Suspense·的实现原理及后续扩展思路,而不是「实现全功能的 Suspense」 在
React中,与Suspense相关的特性:
- Lazy 组件
2. transition fallback (比如 useTransition )- use
Offscreen组件
5. Selective HydrationRSC(React Server Component)
Suspense的架构
Demo:
jsx
<Suspense fallback={<div>loading...</div>}>
<Cpn/>
</Suspense>正常状态,<Suspense/> 渲染子孙组件 挂起状态,<Suspense/> 渲染fallback 其中,造成挂起状态的原因有很多,比如: <Cpn/> 或其子孙是懒加载组件(Lazy文档) <Cpn/> 或其子孙触发并发更新(useTransition ) <Cpn/> 或其子孙是Selective Hydration<Cpn/> 或其子孙使用use 请求数据 总结:凡是涉及 「初始状态」 -> 「中间状态」 -> 「结束状态」 的流程,都可以纳入
jsx
<Suspense/>Suspense实现思路
思路一:只有一个child
缺点:
- 无法保存
children对应状态 - 切换后
children对应DOM需要完全销毁
思路二:有两个child
beginWork 时有选择的返回其中一个child ,但另一个child 也存在于fiber 树中: Offscreen 可以用来实现Keep-Alive 对于下面的代码,一共存在4种流程:
jsx
<Suspense fallback={<div>loading...</div>}>
<Cpn/>
</Suspense>mount时正常流程(对应方法mountSuspensePrimaryChildren)update时正常流程(对应方法updateSuspensePrimaryChildren)mount时挂起流程(对应方法mountSuspenseFallbackChildren)update时挂起流程(对应方法updateSuspenseFallbackChildren)
Suspense工作流程
beginWork时进入上述任一流程
2. completeWork 时对比current Offscreen mode 与wip Offscreen mode ,如果发现下述情况,则标记Visibility effectTag :
mode 从hidden 变为visible
mode``从visible 变为hidden
current === null && hidden
3. commitWork 时处理Visibility effectTag处理Visibility effectTag 时需要找到所有子树顶层Host 节点:
jsx
function Cpn() {
return (
<p>123</p>
)
}情况1,一个host节点:
jsx
<Suspense fallback={<div>loading...</div>}>
<Cpn/>
</Suspense>情况2,多个host节点:
jsx
<Suspense fallback={<div>loading...</div>}>
<Cpn/>
<div>
<p>你好</p>
</div>
</Suspense>如何触发Suspense?
思考一个问题:上述4种流程是在「不同更新触发的render流程」中出现的么? 对于demo中的例子,经历了:
- 正常流程对应
render阶段 - 遇到
use,进入挂起流程 - 进入挂起流程对应
render阶段 - 进入挂起流程对应
commit阶段(渲染loading) - 请求返回后,进入正常流程对应
render阶段 - 进入正常流程对应
commit阶段(渲染Cpn)Suspense涉及到render阶段的一个新流程 ——unwind流程 总结学到的三种流程:beginWork:往下深度优先遍历completeWork:往上深度优先遍历unwind:往上遍历祖辈 Demo中的unwind流程: 数据返回后的正常流程: 涉及到unwind流程的特性:
Suspense
Error Boundary实现use hook与unwind流程
use 可以接收的数据类型:
Thenable
ReactContextunwind 流程如何进行到最近的Suspense ?