首发于公众号 前端从进阶到入院,欢迎关注。
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(value: T) { const [isPending, startTransition] = useTransition(); const [state, setState] = useState(value); useEffect(() =>{ // 当输入更改时,分发并发渲染 startTransition(() =>{ setState(value); }); }, [value]) return state;}
它的使用方式与输入防抖动 hook 相同:
javascript复制代码function Child({ value }) { const deferredValue = useDeferredValue(value); // ...}
并发特性和 Suspense
useTransition 和 useDeferredValue hook 除了可选择启用并发渲染之外,还有一个作用是等待 Suspense 组件完成。
有关 Suspense 及其角色的主题,将在未来的文章中介绍。关注我可以第一时间了解。
原文:www.bbss.dev/posts/react…
关键词: