该系列为 React Conf 2021 分享专题的文字摘录,旨在除核心内容之余,了解分享会上其他的更为细节的内容。
笔记会携带个人理解并可能大量使用自己归纳的话术,可能会产生部分理解偏差, 如有错误理解欢迎指正! 推荐您有时间仍可观看视频内容,来了解原生分享内容。
React 18 for app developers
分享者:Shruti Kapoor
主要内容:
- what's new in React18?
- How to upgrade to React18?
- It's hard to upgrade an exsiting app?
视频地址:React 18 for app developers
React Conf 2021完整视频地址:React Conf 2021 Replay
what's new in React18?(React 18 版本有什么新功能/特性)
- Automatic batching(自动批处理)
- Suspense on the server(Suspense将支持在服务端上进行使用)
- New APIs for app and library developers(提供给普通开发者和库开发者的新的API)
Automatic batching(自动批处理)
React v18 废弃了并发模式,而采用一种并发特性进行取代。
React v18 之前,React 在处理状态更新时,会进行批量更新;但是当状态的更新脱离事件时,将不会批量更新,例如在一个异步方法中。
function handleClick() {
setIsFetching(false);
setError(null);
setFormStatus('success');
} // re-render 1 times
function handleClick() {
fetch('/something').then(() => {
setIsFetching(false); // re-render
setError(null); // re-render
setFormStatus('success'); // re-render
})
}
React v18 将这种情况(脱离事件执行)也纳入批量更新的范围自动批处理,也就是说在 v18 中,上述的三次更新将会变为1次,而这种更少的渲染次数可以带来更高的性能表现。
同时可以借助 flushSync 这一 api 来使用同步的更新模式。
Suspense on the server(Suspense将支持在服务端上进行使用)
什么是服务端渲染技术?
简单来说服务端渲染(SSR server-side render)技术是一种在服务端生成 HTML 并发送到前端的能力,以便于在加载JS包和页面可交互之前,用户可以查看到一部分UI。
在 v18 版本之前,服务端渲染在完成全部渲染后才会返回给浏览器,也就是说在没有完成加载时,将什么都没有。这对于某些场景,如:页面其他部分都渲染的非常快,某一模块(组件)数据加载很慢;这种情况下,按照上述规则,用户需要等待服务器将这一模块渲染完毕后整体返回,才能看到部分UI内容(仍需要去加载js包,并且直至页面可交互)。
在 v18 中,Suspense 将支持在服务端上进行使用,这意味着你可以使用 Suspense 人为的对这些缓慢的组成部分进行包装,令这部分内容延缓加载,后续等待这部分内容加载完毕并且有数据时,服务器渲染将会弹出这部分HTML并将其应用在页面上。
例如可以对一个评论模块进行延缓加载,其代码表现如下:
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
初次呈现的UI视图可能如下所示:
模块加载完毕后如下示意:
通过这样的方式,用户就可以尽早的看到页面,并随着 HTML 片段的渐进加载,页面的内容将逐步完整。特别的,这样的交互将发生在任意 js 和 react 文件加载完毕之前。
总结来说,Suspense 在 SSR 中的应用有以下好处:
- 令加载缓慢的部分不再影响整体的渲染进度(One slow part doesn't slow down the whole page)
- 令呈现尽早的被用户感知并将使用流扩展加载缓慢部分(Show initial HTML early and stream the rest)
- 在服务器端完全集成了代码分割的优化(Code splitting fully integrated with server rendering)
New APIs for app and library developers(提供给普通开发者和库开发者的新的API)
对于普通的应用开发者,我们可以使用到的新 API 有:
- startTransition()
- useTransition()
- useDeferredValue()
这些 API 被称作 concurrent features(并发功能)。其中 useDeferredValue 方法允许你标记一个值,告知 React 以一种低优先级的方式进行处理,它可以帮助您紧急的向用户提供更好视觉反馈,并推迟非紧急组件的渲染(原话为:It helps you give visual feedback to the user for an urgent update and helps you defer to rerender of components that are not as urgent.)从而达到性能优化的结果。
function Demo(props) {
const [filters, mergeFilters] = useMergeState(defaultFilters);
// useDeferredValue
const deferredFilters = React.useDeferredValue(filters);
return (
<Fragment>
<Filters
filters={filters}
/>
<Lists
filters={deferredFilters}
project={project}
/>
</Fragment>
)
}
对于上述例子,filters
为过滤器数据,分别应用于 <Filters />
和 <Lists />
两个组件,其中 <Lists />
组件负责对 project
数据按照 filters
数据进行筛选并展示列表,是一个功能更重的组件,而 <Filters />
组件提供过滤选择功能,并包含一些 hover 高亮渐变的情况。
如若不进行 useDeferredValue
处理,在进行 <Filters />
选择时(列表在选择后刷新), 部分本身配置较差的设备中, <Filters />
组件的 hover 高亮渐变的效果会被列表阻塞,从而产生卡顿的反馈。利用 useDeferredValue
,给 <Lists />
组件传入带有延迟标记的变量,告知 React 尽快返回 UI,并对这一部分较重的模块后置渲染更新,达到不影响高亮渐变,列表后置更新的效果。
上述例子延迟更新的前提是“部分本身配置较差的设备中”,可以理解为计算机本身速度慢的情况下(或者通过chrome控制台开启了CPU节流),只有这种场景下,才会进行延迟更新。(因此可以理解为:useDeferredValue 会根据其内部的一套判别机制来决定是否启用,而启用情况下,应用本身不会出现异常,呈现上会降级处理。)
对于库开发者,可以使用以下新 API:
- useId()
- useSyncExternalStore();
其中 useId 可以为组件生成唯一的 id;useSyncExternalStore 将会在《React 18 for External Store Libraries》中进行单独介绍。
How to upgrade to React18?(怎么升级到 React 18 )
升级 React 18 版本的步骤如下:
-
在项目中安装(或者是升级) react v18 和 react-dom v18 的 npm 包b
-
更改根节点的渲染写法: ReactDOM.render 修改为 ReactDOM.createRoot
// 以前的写法
const container = document.getElementById('app');
ReactDOM.render(<App />, container);
// 修改为下述写法
const container = document.getElementById('app');
const root = ReactDOM.createRoot(container);
root.render(<App />);
It's hard to upgrade an exsiting app?(对已有的 React 应用升级到 v18 版本困难吗?)
大多数应用在升级到 v18 时没有问题,或者说只需要更改少量代码后就可以正常工作。
边缘情况
- StrictMode became stricter(but you can disable it)
严格模式将更加严格
- flushSync() lets you opt out of automatic batching
flushSync()方法允许你对自动化批处理进行开关,当存在不兼容的第三方库或者特定不适用批量更新的场景时,可以通过flushSync()方法进行适配
- Concurrent features may require library updates
项目中如果使用了第三方库,并期望第三方库与 v18 提供的并发特性功能互相配合使用时,可能需要等待该库的维护者进行升级后,才可以使用。