type
status
date
slug
summary
category
tags
password
icon
众所周知(其实很多人没有意识到),React的默认渲染行为是同步的,React总是在我一个操作或者状态更新后再执行下一个操作或状态更新。在大部分场景下,这种即时响应是理想的,因为它确保了UI与内部状态保持紧密同步。但在密集或资源繁重的更新场景下——如加载大量数据时,这种同步行为可能导致整个应用的UI卡顿甚至没有响应。我们把这种UI卡顿现象叫做“阻塞”,当你遇到这种情况时,你的leader往往会让你进行用户体验优化🐶。
React v18开始,官方引入了并发模式(Concurrent Mode)和一些相关的Hooks,其中之一就是useTransition。开发者可以将某些状态更新标记为“可中断”的,从而允许React在必要时打断这些更新,先处理其他更为紧急的任务。我们把这种渲染效果称作“非阻塞UI”。
在这篇文章中,我们就来探讨useTransition的工作原理,如何在实际应用中使用它。

useTransition基础

首先,我们要明白useTransition的设计初衷:在React的并发模式下,允许我们中断或延后某些状态更新,以便于能够在长时间的计算或数据拉取时保持UI的响应性。

用法定义

  • isPending是一个布尔值,当过渡状态仍在进行中时,其值为true;否则为false
  • startTransition:是一个函数,当你希望启动一个新的过渡状态时调用它。

工作原理

  1. 并发模式下的状态更新分类: 在React的并发模式中,不是所有的状态更新都被视为等同的。React将更新分为不同的优先级类别,其中某些更新(如输入处理)被认为是更加紧急的,而其他更新(如从服务器获取数据)则可以中断或者延后更新。
  1. 使用startTransition进行状态更新: 当你使用startTransition函数进行状态更新时,你实际上告诉 React:这个更新不是非常紧急的,如果有更重要的更新要处理,你可以中断或延后这个次要更新。
  1. isPending的用途: isPending 为我们提供了一个标识,告诉我们是否有一个startTransition正在执行。我们可以根据isPending来设置过渡状态的样式。

使用范围和注意事项

  • useTransition仅在开启React并发模式的时候才有效
    • 只有当你能访问某个状态的set函数时,你才能将更新包装进useTransition中。
    • 传递给startTransition的函数必须是同步的,而不能是异步的。
      • 如果你想根据某个 prop 或自定义 Hook 的值来启动一个过渡,那么你应该尝试使用useDeferredValue。这是下一篇介绍的hook,此处不展开。
      • 不能用于控制文本输入。因为输入框是需要实时更新的,如果用useTransition降低了渲染优先级,可能造成输入“卡顿”。
      • 不要在startTransition内部使用setTimeout,如果一定要用setTimeout,你可以在startTransition外层使用
        • 前面说到很多次“中断或延后更新”,那么什么时候中断,什么时候延后更新?最简单的理解:被useTransition包裹的同一个状态多次更新,只会渲染最后一个,前面的都算中断(仅UI层面,如:长列表多次请求);不同组件触发不同状态的更新,被useTransition包裹的状态优先级较低,被中断后会等高优先级的状态更新完成后继续更新(如:复杂图表渲染被中断,会在高优先级状态更新后,继续处理图表的渲染)。

        示例

        有无useTransition的对比

        想象一个场景,页面上有多个tab,其中一个请求耗时较长,我们快速点击tab切换内容,但总是会在请求耗时的tab上卡顿一下,代码如下:
        如果我们想用useTransition保持UI的响应,只需要用startTransition包裹切换选项卡的set
        这样我们快速切换tab,无论点到哪一个tab都不会卡顿。

        useTransitionSuspense实现路由流畅切换

        当与路由结合使用时,React.Suspense允许我们延迟渲染新的路由内容,直到所需的数据被完全加载。而useTransition则允许我们可控地开始这种可能导致UI变化的过渡——导航到新页面。
        例如这个示例:
        通过这种方式,我们可以优雅地处理路由切换,并确保在数据加载时为用户提供一个流畅的体验。

        结语

        useTransition带来的是“可中断”的异步UI渲染,当实际工作中遇到卡顿的现象,不妨想想是否能用useTransition解决。

        专栏资源

        专栏博客地址:精读React Hooks
        专栏演示站:React Hooks Demos
        专栏源码仓库:👉Github - Source Code
        国内镜像仓库:👉Gitee — Source Code
         
        专栏文章列表:
         
        精读React hooks(十):使用useDeferredValue延迟状态更新精读React hooks(八):我们为什么需要useCallback