官方博客:
最重要的两个新特性:Concurrent Mode 并发渲染和 Suspense 异步加载数据模式
1. Concurrent Mode
Concurrent 并发模式渲染 UI,把一整个 React 组件树的渲染计算过程拆成更小的步骤,使其可以被中断,以便优先处理更高优先级(悬停、文本输入等)的渲染。
这里 React 这么做的目的,也着重于用户交互相关的部分的 即时反馈,把人类视角的一部分触发操作赋予了更高的优先级。
为了配合这种模式的工作,另外提供了几个 API 给开发者使用:startTransition
, useTransition
, useDeferredValue
, useSyncExternalStore
, useInsertionEffect
。
2. 数据获取用的 Suspense 组件
实现把 Loading
状态也写到组件树里面,与 ErrorBoundary
一起,提供一种更简洁明了的 UI 表达,大多数非特殊场景下可以替代反反复复地写各类数据 loading、error 状态判断的逻辑。
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
<ErrorBoundary fallback={<h2>Could not fetch posts.</h2>}>
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline />
</Suspense>
</ErrorBoundary>
</Suspense>
);
}
关于背后的考虑,官方的 说法 是,构建 UI 的过程有两类影响用户体验的瓶颈(bound),以及对应的解决思路:
- CPU-bound:创建 DOM 节点 / 运行组件渲染部分的代码的 CPU 开销,运行时间长会导致大型页面交互上的卡顿,解决方式是,通过拆成更小步骤搞优先级调度避免阻塞用户交互。
- IO-bound:IO 天然地延迟相对高,相对应需要空白的 Loading 状态处理,而添加 loading 状态的成本和开发体验相对较差,通过 Suspense 的形式也让代码逻辑组合更清晰些。
另外还有一个 ReactDOM 处理服务端渲染的 Server Component 相关的更新,createRoot
/ hydrateRoot
,针对 Node 和边缘计算场景的 renderToPipeableStream
/ renderToReadableStream
等,也是 React 未来着力的其中一个方向,看样子也是希望把 Web 站点可以做的更灵活和快速。