767 字
4 分钟
useTransition

它标记的是「这次更新不急」#

const [isPending, startTransition] = useTransition()

官方原文:useTransition 不接受任何参数,返回 [isPending, startTransition]。

这一条要专门写出来,因为网上大量文章还在教 useTransition({ timeoutMs: 1000 })。那是 React 18 实验期的写法,稳定版没有这个参数,抄进去会直接失效。

回调会立刻执行#

这是最常被讲错的一点。官方给了一段会依次打印 1、2、3 的代码:

console.log(1)
startTransition(() => {
console.log(2)
setPage('/about')
})
console.log(3)

startTransition 不会把函数推到「主线程空闲时」再跑。React 立刻调用它,被标记成过渡的只是它执行期间安排的 state 更新。所以回调里不要写任何依赖「执行时机」的逻辑。

它带来的两件事#

过渡更新是可中断的。用户在切换视图的过程中继续输入,React 会放弃这次渲染,先去处理输入。

过渡更新不会把已经显示的内容换成加载态。配合 Suspense 时,它会在已显示内容的边界内等新内容就绪,而不是先闪一下 fallback。

什么时候用它#

典型场景是「切换一个视图,新视图渲染慢」。用户点了标签页,输入框和其他部分仍然要立刻响应。

function TabContainer() {
const [tab, setTab] = useState('about')
const [isPending, startTransition] = useTransition()
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab)
})
}
return (
<>
<TabButton isActive={tab === 'about'} action={() => selectTab('about')}>关于</TabButton>
<TabButton isActive={tab === 'posts'} action={() => selectTab('posts')}>
文章{isPending && '(加载中)'}
</TabButton>
</>
)
}

isPending 从第一次调用 startTransition 起变为 true,直到所有过渡完成才回到 false。它适合做按钮上的小状态,而不是整页的加载图标。

不能控制文本输入#

过渡更新不能用来控制输入框的值,输入必须同步更新:

// 不行:输入会变得一顿一顿
startTransition(() => {
setText(e.target.value)
})

想做到「输入立即响应、结果列表慢一点」,用 useDeferredValue。

await 之后要再包一层#

startTransition(async () => {
await save()
startTransition(() => setStatus('done')) // 不包,这次更新不算过渡
})

await 之后的 state 更新不再算过渡,因为 React 在这个边界上丢了上下文。官方说这是当前的已知限制,将来会修。

官方更推荐的高层写法#

useTransition 参考页里点名:常见的异步提交优先用 useActionState、<form> 的 action、Server Functions,它们会替你处理请求顺序。自己包 startTransition 一般是写自定义 Hook 或库的时候才需要。

四条边界#

回调里的计算是同步跑的。过渡只推迟「状态更新引起的渲染」,不会把回调里那段筛选或计算变快。所以「筛选一万条数据」的开销放在回调里并不能被推迟,那种场景要用 useDeferredValue 或把慢组件抽出来。

回调抛错或返回 reject 的 Promise 时,用错误边界来接。官方的用法就是外面包一层 ErrorBoundary。

同时有多个过渡时,React 目前会把它们合并处理,这是已知限制,将来可能改。

它需要 React 18 及以上。

第 28 篇,共 39 篇本文属于系列

useTransition
https://www.choria.top/posts/hook-use-transition/
作者
乔瑞雅·克林威尔
发布于
2026-05-02
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取

最后更新于 ,距今已过 190 天

部分内容可能已过时