跳到主要内容

延迟值

useDeferredValue 如何让新输入与旧结果同时显示?​

  • 两阶段显示: 紧急渲染先使用旧的 deferredValue,随后在后台尝试新值;后台工作可被下一次输入打断并重启;
  • 输入与结果: input 读取即时值,昂贵列表读取延迟值,让打字反馈不必等待列表完成;
const [query, setQuery] = useState("");
const deferredQuery = useDeferredValue(query);
const stale = query !== deferredQuery;

const view = (
<>
<input value={query} onChange={(event) => setQuery(event.target.value)} />
<div style={{ opacity: stale ? 0.5 : 1 }}>
<Results query={deferredQuery} />
</div>
</>
);

首次渲染没有旧值时返回什么?​

  • 默认行为: 不传第二参数时,初次返回当前 value,因为还没有旧版本可复用;
  • 初始后备: useDeferredValue(value, initialValue) 可让首次先使用 initialValue,再在后台渲染 value;
  • Transition 内: 更新已经属于 Transition 时直接使用新 value,不再额外启动延迟渲染;
function Preview({ query }) {
const deferredQuery = useDeferredValue(query, "");
if (deferredQuery === "") return <p>准备预览……</p>;
return <Results query={deferredQuery} />;
}
  • 初始值选择: initialValue 必须是下游组件能正确处理的值,不能为了延迟渲染传入不符合接口的占位对象;

为什么它不等于防抖或请求节流?​

  • 没有固定等待: React 在完成紧急渲染后便尝试后台工作,快设备上可能很快完成,慢设备上可持续让位;
  • 网络请求: 不会自动减少请求次数,缓存、去重和防抖应在数据层另行实现;
  • 缓存配合: 昂贵子组件需要能够跳过即时渲染,例如使用 memo 或编译器优化,否则旧值下也可能反复做同样工作;

延迟渲染挂起时用户会看到什么?​

  • Suspense 配合: 后台新值挂起时保留旧内容,数据准备好后再展示新内容;可通过新旧值比较显示过期提示;
  • Effect 时机: 未提交的后台渲染不运行 Effect,不能把后台尝试当作已经显示的新 UI;
  • 引用风险: 每次渲染新建对象作为 value 会不断触发后台工作,优先使用原始值或稳定对象;