useDeferredValue 钩子

2025-06-08

useDeferredValue 钩子

React 18 的非 Beta 版本引入了两个新的 React Hook,用于控制渲染缓慢的内容并提升性能。useDeferredValue Hook就是其中一种简单易用但难以理解的 Hook。在本文中,我将介绍它的工作原理以及何时应该使用它。
首先考虑以下代码:

const ListItems= () =>{

  const [txtValue, setTxtValue] = useState("")

  const expensiveFunction = useMemo(() => {
    return getComplexValue(txtValue)
  }, [txtValue])

  function handleChange(e) {
    setTxtValue(e.target.value)
  }

  return <input type="text" value={txtValue} onChange={handleChange} />

}
Enter fullscreen mode Exit fullscreen mode

这段代码是一个清晰的组件,包含一个状态和一个 expensiveFunction 变量,该变量的状态会对其产生副作用。每当输入值发生变化时,name 状态就会更新,状态更新完成后,整个组件都会重新渲染。由于 name 状态的影响,ExpensiveFunction 在渲染过程中会重新计算。
乍一看这似乎没什么问题,但 useMemo 中的代码计算成本很高,可能会出现性能问题。

const ListItems= () =>{

  const [txtValue, setTxtValue] = useState("")

  const list = useMemo(() => {
    return largeList.filter(item => item.name.includes(txtValue))
  }, [txtValue])

  function handleChange(e) {
    setTxtValue(e.target.value)
  }

  return <>
    <input type="text" value={txtValue} onChange={handleChange} />
    {list.map(item => <Item key={item.id} item={item} />)}
  </>

}
Enter fullscreen mode Exit fullscreen mode

想象一下,API 中有一个大型列表,使用名称状态来过滤列表项。过滤长列表并将其渲染到屏幕上需要时间,而且每次输入值发生变化时,处理过程都会非常缓慢。这是一个性能问题,会导致用户界面使用起来非常缓慢。
当你尝试在输入框中输入内容时(如本例所示),处理速度非常慢,大约需要一秒钟才能更新输入框。由于渲染和处理,列表渲染耗时非常长。这​​时 useDeferredValue 就派上用场了。

解释 useDeferredValue

useDeferredValue hook 通过在估算某些信息之前添加延迟来解决渲染缓慢的问题。其工作原理类似于防抖和节流,因为我们的延迟值仅在重要的状态更新完成后才计算。

const ListItems= () =>{

  const [txtValue, setTxtValue] = useState("")
  const deferredName = useDeferredValue(txtValue)

  const list = useMemo(() => {
    return largeList.filter(item => item.name.includes(deferredName))
  }, [deferredName])

  function handleChange(e) {
    setTxtValue(e.target.value)
  }

  return <>
    <input type="text" value={txtValue} onChange={handleChange} />
    {list.map(item => <Item key={item.id} item={item} />)}
  </>

}
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,我们通过使用 useDeferredValue hook 解决了这个问题。它接受一个参数,即你想要配置节流/防抖动的值。它会返回传入值的延迟版本。这意味着即使 name 变量发生变化,deferredName 的值也不会改变,因为 useDeferredValue 不会立即更新 deferredName 的值。

这给了我们的组件足够的时间用新的 name 值完全渲染,因为我们的列表不会在等待 deferredName 更改时尝试更新自身。这使得应用程序响应更快,因为输入会立即更新,而列表会稍后更新。

列表延迟的原因是我们将 useMemo 代码改为依赖 deferredName 而不是实际名称。这意味着,如果我们更改名称,deferredName 将等待 UI 更新到输入字段中新的名称值后才会更新。如果我们在短时间内更改输入(例如,在输入框中快速输入),deferredName 值将保持不变,列表将不会更新。在名称值更改暂停之前,唯一会更新的是名称变量。一旦我们停止输入,React 将使用最新的名称值更新 deferredName 值并重新渲染列表。

在上面的示例中,使用 useDeferredValue 钩子时,列表的行为符合预期。输入时,您可以看到输入框快速更新,但列表本身却没有更新。列表的旧值会保留在屏幕上,直到有足够的延迟使其自身渲染到屏幕上。

useDeferredValue hook 简单易用,但你不应该一直使用它。只有当你的代码遇到性能问题并且已经用尽所有其他方法时,才应该使用它。如果一直使用它,你的应用性能会下降,因为 React 会被迫执行额外的渲染。这是因为它会同时执行初始重新渲染和延迟重新渲染,而如果没有 useDeferredValue,它本可以在一次更新中完成这两项操作。

因此,useDeferredValue 钩子使得处理缓慢、计算复杂的重新渲染变得更加简单,因为我们现在可以告诉 React 将这些更新推迟到稍后,从而使您的应用程序对用户来说显得性能更高。

鏂囩珷鏉ユ簮锛�https://dev.to/fpaghar/usedeferredvalue-hook-29m9
PREV
如何使用 git - git 工作流程概述
NEXT
微前端架构