首发于公众号 前端从进阶到入院,欢迎关注。
React v18.0 引入了一项期待已久的新功能——并发模式!
不幸的是,尽管有大量的资源解释如何使用它,但解释它如何工作的资源却不太充足。
由于这是一个底层特性,理解 React 关于并发的概念并不是必须的,但也无妨!
这篇文章并不试图全面介绍 React 的并发 API 和最佳实践。最好结合链接在这里的 React 文档页面阅读。
什么是 React 并发模式?
React 并发的基本原理是重构渲染过程,使在渲染下一个视图时,当前视图保持响应性。
并发模式是 React 团队提升应用性能的一个提案。它的想法是将渲染过程分成可中断的工作单元。
在幕后,这将通过在requestIdleCallback() 调用中包装组件渲染来实现,让应用在渲染过程中保持响应性。
所以,如果将类似如下的“阻塞模式”实现:
scss复制代码function renderBlocking(Component) {for (let Child of Component) {renderBlocking(Child);}}
那么将会这样实现“并发模式”:
scss复制代码function renderConcurrent(Component) {// 如果状态已经过时,打断渲染进程if (isCancelled) return;for (let Child of Component) {// 等待浏览器不忙(没有要处理的输入)requestIdleCallback(() => renderConcurrent(Child));}}
阅读这篇实践指南:如何避免阻塞事件循环,以了解为什么这可以使应用程序保持响应!
如果你好奇 React 实际上如何做到这一点,请看看 React 的 scheduler 包的实现。在最初使用requestIdleCallback之后,React 切换到了 requestAnimationFrame,之后又切换到了用户空间计时器。
没有模式,只有特性
由于向后兼容性的原因,并发模式并没有实现。
相反,React 团队转向了并发特性,一组新的 API,用于选择性地启用并发渲染。到目前为止,React 已经引入了两个新的 hook 来实现并发渲染。
useTransition
useTransition hook 返回两个元素:
布尔标志 isPending,如果并发渲染正在进行则为 true 函数 startTransition,用于分发一个新的并发渲染
为了使用它,请在 setState 调用中使用 startTransition 回调。
javascript复制代码function MyCounter() {const [isPending, startTransition] = useTransition();const [count, setCount] = useState(0);const increment = useCallback(() => {startTransition(() => {// 并发运行这个更新操作setCount(count => count + 1);});}, []);return (<>{isPending ? "Pending" : "Not Pending"}// 受益于并发特性的组件
试试看:
译者注:这里其实有 200 多个 Input 框,在 Non-Transition 的情况下,点击 Count 按钮后会感觉到 UI 界面明显有卡顿,而 Transition 模式则非常流畅。
从概念上讲,状态更新检测它们是否被包装在 startTransition 中,以决定是安排阻塞渲染还是并发渲染。
ini复制代码function startTransition(stateUpdates) {isInsideTransition = true;stateUpdates();isInsideTransition = false;}function setState() {if (isInsideTransition) {// 安排并发渲染} else {// 安排阻塞渲染}}
useTransition 的一个重要警告是,它不能用于受控输入。对于这些情况,最好使用 useDeferredValue。
useDeferredValue
useDeferredValue hook 是一个便捷的 hook,适用于你没有机会将状态更新包装在 startTransition 中,但仍希望并发运行更新的情况。
其中一个例子是,子组件从父组件接收一个新值。
从概念上看,useDeferredValue 是一个防抖动效果,可以实现如下:
scss复制代码function useDeferredValue
它的使用方式与输入防抖动 hook 相同:
javascript复制代码function Child({ value }) {const deferredValue = useDeferredValue(value);// ...}
并发特性和 Suspense
useTransition 和 useDeferredValue hook 除了可选择启用并发渲染之外,还有一个作用是等待 Suspense 组件完成。
有关 Suspense 及其角色的主题,将在未来的文章中介绍。关注我可以第一时间了解。
原文:www.bbss.dev/posts/react…
如果觉得《理解 React 18 的“并发特性” 就这么简单》对你有帮助,请点赞、收藏,并留下你的观点哦!