【结论】 例子能跑,但「把过滤结果存进另一个 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,也少一处"两份数据不同步"的风险。

几个真实的坑:

  1. 受控输入的值不能塞进 transition。`startTransition(() => setValue(e.target.value))` React 会警告并回退成同步更新,因为输入框不允许被"打断"。
  2. 回调必须是同步的。传 `async` 函数的话,`await` 之后的 `setState` 不再被标记为过渡——这是 18 和 19 行为差异最大的一处。