跳到主要内容

React.useTransition

React.useTransition 是 React 18 引入的一个 并发特性(Concurrent Features) Hook,用于将非紧急的更新标记为“过渡(transition)”,从而让 React 能够优先处理高优先级任务(如用户输入、动画),避免界面卡顿,提升用户体验。


✅ 核心概念一句话总结:

useTransition 让你可以把“不那么紧急”的状态更新(比如搜索、筛选、切换标签页)标记为低优先级,React 会先响应用户交互,再处理这些更新,保持 UI 流畅。


🔧 基本用法

import { useTransition, useState } from 'react';

function App() {
const [isPending, startTransition] = useTransition();
const [input, setInput] = useState('');
const [items, setItems] = useState(largeList);

const handleChange = (e) => {
const value = e.target.value;
setInput(value);

// 将“过滤列表”这个操作标记为 transition(低优先级)
startTransition(() => {
setItems(
largeList.filter(item =>
item.name.toLowerCase().includes(value.toLowerCase())
)
);
});
};

return (
<div>
<input value={input} onChange={handleChange} />

{/* 显示加载状态(可选) */}
{isPending && <div>正在筛选...</div>}

<List items={items} />
</div>
);
}

📌 useTransition 返回什么?

const [isPending, startTransition] = useTransition();
返回值类型说明
isPendingboolean表示是否有 transition 正在进行(可用于显示 loading)
startTransitionfunction一个函数,接收一个回调,该回调内的状态更新会被标记为“过渡更新”

⚡ 为什么需要 useTransition

场景:在大型列表中搜索

  • 用户在输入框打字(高优先级:必须即时响应)
  • 每次输入都要过滤 10,000 条数据并重新渲染(低优先级:可以稍后处理)

不用 useTransition 的问题

  • 打字时界面卡顿(因为 React 被大计算阻塞)
  • 输入延迟,体验差

用了 useTransition

  • 输入框立即响应(高优先级任务优先执行)
  • 列表更新被“推迟”到浏览器空闲时再处理(低优先级)
  • 即使列表还没更新完,用户仍可继续输入或点击其他按钮

💡 React 会中断低优先级的渲染,去处理新的高优先级事件(如新按键),实现“可中断渲染”。


🆚 对比:普通更新 vs Transition 更新

行为普通 setStatestartTransition(setState)
优先级高(立即渲染)低(可中断、可推迟)
是否阻塞 UI
触发 Suspense fallback❌ 不会✅ 会(如果配合 Suspense)
isPending 状态有(可用于 loading 提示)

🧪 实际效果演示

假设你有一个慢操作:

// 模拟耗时计算
const filterItems = (query) => {
const start = Date.now();
while (Date.now() - start < 2000) {} // 阻塞 2 秒!
return originalList.filter(...);
};
  • 不用 transition:点击按钮后,整个页面冻结 2 秒。
  • 用 transition:点击后 UI 依然可交互(比如还能点取消),2 秒后结果才出现。

⚠️ 注意事项

1. 只能用于状态更新

startTransition(() => {
setCount(c => c + 1); // ✅ OK
fetchData(); // ❌ 无效!异步操作不会被标记为 transition
});

startTransition 只影响 同步的状态更新。如果你要结合数据请求,需配合 Suspense + 缓存(如 Relay、SWR)。


2. 不要用于紧急更新

以下情况不要用 useTransition

  • 表单提交
  • 按钮点击反馈(如“已添加到购物车”)
  • 任何需要立即视觉反馈的操作

3. useDeferredValue 的区别

Hook用途
useTransition主动触发一个低优先级更新(你控制何时开始)
useDeferredValue被动延迟某个值的更新(常用于输入防抖场景)
// useDeferredValue 示例
const deferredQuery = useDeferredValue(inputValue);
// 当 inputValue 变化快时,deferredQuery 会滞后,避免频繁重渲染

✅ 最佳实践

  1. 用于搜索、筛选、标签切换等“非即时”操作
  2. 配合 isPending 显示微弱 loading(不要用全屏遮罩!)
    {isPending && <Spinner size="small" />}
  3. 不要包裹异步逻辑(如 API 调用),它只影响 React 的渲染调度

🌐 浏览器兼容性

  • 需要 React 18+
  • 依赖 React 的并发渲染机制(自动启用,无需额外配置)

✅ 总结

关键点说明
目的避免非关键更新阻塞 UI,提升响应性
核心 APIconst [isPending, startTransition] = useTransition()
使用方式把 setState 包在 startTransition(() => { ... })
适用场景搜索、筛选、复杂列表更新等
不适用场景表单提交、即时反馈、异步请求

💡 记住
“用户输入是皇帝,其他都是臣民。”
useTransition 给“臣民”排队,让“皇帝”优先通行!

这是构建流畅、专业级 React 应用的重要工具之一。