← 返回题目列表

useDeferredValue 的作用是什么?和防抖有什么区别?

中等 第 26 / 27 题 更新于 2026/07/29
ReactuseDeferredValueReact18性能优化

简化版

useDeferredValue 会返回一个可延迟更新的值,让高优先级 UI 先更新,依赖延迟值的重组件稍后更新。它不是防抖,不按固定时间等待,也不会减少输入变化本身,而是把慢渲染放到较低优先级。

详细版

常见场景是输入框使用实时值,大列表使用延迟值。

const [text, setText] = useState('')
const deferredText = useDeferredValue(text)

return (
  <>
    <input value={text} onChange={e => setText(e.target.value)} />
    <BigList keyword={deferredText} />
  </>
)

输入框会尽快响应 textBigList 根据 deferredText 稍后更新。防抖是时间策略,例如 300ms 后触发;useDeferredValue 是调度策略,由 React 根据渲染压力安排。

完整版教学

一、它解决的是派生重 UI 拖慢输入

有些页面一个状态会同时驱动轻 UI 和重 UI。 输入框显示字符很轻,但下面的大列表过滤和渲染很重。 如果二者使用同一个实时值,输入每变一次都可能带着大列表一起更新。

text 变化
├─ input value 更新 轻
└─ BigList 过滤和渲染 重

当 BigList 有 5000 行时,输入一个字符就触发大量渲染。 useDeferredValue 让 BigList 使用“稍慢一拍”的值,使输入框先保持流畅。

二、deferred value 是旧值暂时可用

useDeferredValue(text) 返回的值可能暂时落后于 text。 React 会在紧急更新完成后,再安排依赖 deferred 值的渲染。 这意味着 UI 中可能同时存在新输入和旧结果。

const deferredQuery = useDeferredValue(query)
const isStale = query !== deferredQuery
用户输入 react
query: react
deferredQuery: rea
列表仍显示 rea 的结果
稍后 deferredQuery 追上 react

可以用 isStale 给列表加透明度或提示。 这样用户知道结果正在追赶输入。

三、它和 useTransition 的角度不同

useTransition 是包住某次状态更新,把更新标记为非紧急。 useDeferredValue 是拿一个值的延迟版本,让使用该值的子树降低更新紧急度。 一个偏“更新动作”,一个偏“值的消费”。

对比useTransitionuseDeferredValue
作用对象状态更新某个值
是否有 pending没有直接 pending
常见位置事件处理里渲染逻辑里
典型场景手动标记慢更新子组件消费延迟值

如果你能控制 setState 的地方,用 transition 很直接。 如果值来自 props 或上层,当前组件不能控制更新来源,deferred value 更方便。

四、它不是防抖,因为没有固定等待时间

防抖常写成“输入停止 300ms 后再执行”。 useDeferredValue 不承诺等待固定毫秒数。 React 会根据当前渲染压力安排延迟更新。

防抖:
固定 300ms 等待

useDeferredValue:
输入先更新
重 UI 在较空闲或较低优先级时追上

如果业务要求“用户停下 500ms 才请求接口”,应该用防抖。 如果只是希望输入不卡,而结果可以稍后渲染,用 useDeferredValue

五、它仍需要配合 memo 才能发挥效果

如果重组件没有 memo,父组件渲染时它仍可能跟着执行。 通常会把依赖 deferred 值的重组件拆出去,并用 memo 降低无关重渲染。

const BigList = memo(function BigList({ keyword }) {
  // 重过滤和重渲染
})

假设父组件因为输入更新渲染 10 次。 如果 BigList 每次都跟着重算,deferred 的价值会被削弱。 拆分组件、memo、虚拟列表和 deferred value 经常要配合使用。

六、不要用于必须强一致的显示

有些 UI 必须和输入值完全同步,例如密码强度提示、表单校验错误、金额计算。 如果延迟显示,用户可能误解当前状态。 这类内容不适合使用 deferred value。

记忆钩子:deferred value 是“慢镜头副本”,输入用新值,重内容用慢一拍的值。

这个比喻能帮助区分它和防抖。 防抖是等用户停,deferred 是让慢 UI 追。

七、常见误区与追问

  • 误区:useDeferredValue 是防抖 Hook。 它不按固定时间等待,而是交给 React 调度较低优先级更新。
  • 误区:所有值都可以延迟。 强一致展示、表单校验和关键反馈不适合延迟。
  • 误区:用了 deferred 就不需要优化列表。 大列表仍要配合 memo、虚拟列表或减少计算量。
  • 追问:如何判断列表是否落后? 可以比较原值和 deferred 值,例如 query !== deferredQuery
  • 追问:它和 useTransition 最大区别是什么? transition 标记更新,deferred value 延迟消费值。
  • 追问:值来自父组件怎么办? 当前组件无法控制父级 setState 时,使用 useDeferredValue 很合适。

八、加强记忆

useDeferredValue 记成“延迟值副本”。输入框看实时值,大列表看延迟值;它解决交互响应,不替代防抖请求;要配合组件拆分、memo 和虚拟列表,别指望一个 Hook 把所有重活变轻。