【结论】 例子能跑,但「把过滤结果存进另一个 state」是这篇里最容易踩的坑,同样的效果用 useDeferredValue 两三行就够了。
先说返回值:useTransition() 返回的是 [isPending, startTransition],顺序写反不报错,只会莫名其妙永远 pending 或直接调用崩溃——你结尾那句"注意返回"应该就是说这个。
过滤列表其实不用复制一份派生状态:
const [query, setQuery] = useState('');
const deferred = useDeferredValue(query);
const list = useMemo(
() => ALL_ITEMS.filter(it => it.name.includes(deferred)),
[deferred]
);
setQuery 仍是紧急更新,deferred 落后一拍,中途新输入会直接丢弃上一次渲染。少一个 state,也少一处"两份数据不同步"的风险。
几个真实的坑:
- 受控输入的值不能塞进 transition。
startTransition(() => setValue(e.target.value))React 会警告并回退成同步更新,因为输入框不允许被"打断"。 - 回调必须是同步的。传
async函数的话,await之后的setState不再被标记为过渡——这是 18 和 19 行为差异最大的一处。
正式会员









