React 并发特性实战:用 useTransition 与 useDeferredValue 让 UI 保持响应
test12026-09-130 次阅读
问题背景
在列表搜索、大数据过滤这类交互里,用户输入触发的重计算会占用主线程,导致输入框卡顿、打字掉帧。React 18 引入的并发特性把更新分为"紧急"与"过渡"两类,让用户输入这类紧急更新优先渲染,重计算放到后台。
核心 API
- useTransition:返回一个 [isPending, startTransition],把非紧急更新包进 startTransition。
- useDeferredValue:直接延迟某个派生值的更新,等价但更简洁。
- useMemo:配合延迟值做缓存,避免每次输入都重算。
可运行示例
import { useState, useTransition, useDeferredValue, useMemo } from 'react';
const ALL = Array.from({ length: 20000 }, (_, i) => ({
id: i,
name: `User-${i}`,
}));
export function UserFilter() {
const [query, setQuery] = useState('');
const [isPending, startTransition] = useTransition();
// 输入框立即更新;过滤用的 query 延迟到空闲时再变
const deferredQuery = useDeferredValue(query);
const list = useMemo(
() => ALL.filter((u) =>
u.name.toLowerCase().includes(deferredQuery.toLowerCase())),
[deferredQuery],
);
function onChange(e: React.ChangeEvent<HTMLInputElement>) {
const v = e.target.value;
setQuery(v); // 紧急更新:输入框不卡
startTransition(() => {
// 此处可做额外重计算,React 会在空闲时提交
});
}
return (
<div>
<input value={query} onChange={onChange} placeholder="搜索用户" />
{isPending && <span>过滤中…</span>}
<ul>
{list.slice(0, 100).map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
</div>
);
}
要点与坑
- useDeferredValue 的旧值会先渲染,输入期间不会卡白屏,仅在"慢"的派生结果就绪后替换。
- 不要在 startTransition 里放 setState 之外的副作用;副作用仍需用 useEffect 管理。
- 过渡更新可被更高优先级的输入打断,因此不要依赖过渡内状态的"最终一致性"做关键流程。
- 列表渲染配合虚拟化的 windowing 方案效果最佳,二者正交可叠加。
T
test1
文章作者
问题背景 在列表搜索、大数据过滤这类交互里,用户输入触发的重计算会占用主线程,导致输入框卡顿、打字掉帧。React 1...
- 分类
- 技术
- 发布时间
- 2026-09-13
- 字数
- 约 1533 字
- 阅读
- 0 次
