首发于公众号 前端从进阶到入院,欢迎关注。

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…

关键词: