首页
Preview

🕒 最佳实践:使用 React useDeferredValue 提升性能

React 18引入了一种新的钩子useDeferredValue,可以通过延迟UI的某些部分的更新来提高应用程序的性能和用户体验。useDeferredValue钩子允许你延迟更新UI的一部分,直到下一个渲染周期。让我们探讨一下useDeferredValue的作用,如何使用它以及一些使用案例。

内容

  • 什么是useDeferredValue?
  • 为什么使用useDeferredValue?
  • 何时使用useDeferredValue?
  • useDeferredValue的最佳实践
  • 结论
  • 了解更多

什么是useDeferredValue?

useDeferredValue是一个React钩子,它接受一个值并返回一个新的值副本,该副本将延迟到更紧急的更新。延迟的值在初始渲染期间与原始值相同,但在后续渲染中会有延迟更新。这种延迟允许React优先处理其他更重要的更新,例如打字或滚动。

例如,如果你有一个输入字段和一个依赖于输入值的项目列表,你可以使用useDeferredValue来延迟更新列表,直到输入值稳定。这样,你可以避免不必要的重新渲染,并保持输入字段的响应性。

useDeferredValue的语法非常简单:

const deferredValue = useDeferredValue(value);

value参数可以是任何类型的值,例如字符串、数字、对象或数组。钩子将返回一个延迟版本的值,当React优先处理更重要的更新时,该值将在后台更新。

为什么使用useDeferredValue?

useDeferredValue的主要用例是在加载新内容时显示旧内容。这可以帮助避免不必要的重新渲染和不流畅的UI过渡,从而提高应用程序的性能和用户体验。

例如,假设你有一个搜索功能,允许用户过滤一个大型项目列表。过滤大型列表可能会消耗大量计算资源并需要很长时间才能完成。如果你在每次按键时更新UI,你将导致频繁的重新渲染,这会使输入变得不流畅和不响应。此外,你将显示与用户查询不相关的中间结果。

function SearchPage() {
  const [query, setQuery] = useState("");
  const list = useMemo(() => {
    // Filtering through large list impacts performance
    return largeList.filter((item) => item.name.includes(query));
  }, [query]);

  const handleChange = (event) => {
    setQuery(event.target.value);
  };

  return (
    <>
      <input
        type="text"
        value={query}
        onChange={handleChange}
        placeholder="Search"
      />
      {list.map((item) => (
        <SearchResultItem key={item.id} item={item} />
      ))}
    </>
  );
}

我们有一个状态变量query,用于存储输入值,以及一个记忆化变量list,根据查询筛选一个大型项目数组。这段代码的问题在于,每次用户在输入字段中输入时,React都会使用更新后的查询和列表重新渲染组件。这可能会导致性能问题并使输入字段变得不流畅。

更好的方法是使用useDeferredValue来延迟更新列表,直到用户停止输入。这样,你可以在新列表在后台计算时显示先前的列表。你还可以通过添加一些视觉提示(例如旋转器或淡入效果)来表示列表已过时。

function SearchPage() {
  const [query, setQuery] = useState("");
  const deferredQuery = useDeferredValue(query);

  // Filter through a large list based on the deferred query
  const list = useMemo(() => {
    return largeList.filter((item) => item.name.includes(deferredQuery));
  }, [deferredQuery]);

  // Indicate that the list is stale if it doesn't match the query
  const isStale = deferredQuery !== query;

  const handleChange = (event) => {
    setQuery(event.target.value);
  };

  return (
    <>
      <input
        type="text"
        value={query}
        onChange={handleChange}
        placeholder="Search"
      />
      {isStale && <Spinner />}
      {list.map((item) => (
        <SearchResultItem key={item.id} item={item} isStale={isStale} />
      ))}
    </>
  );
}

现在,当用户在输入字段中输入内容时,React将首先尝试使用旧查询和列表重新渲染组件(因此它将返回旧值),然后在后台尝试使用新查询和列表重新渲染组件(因此它将返回更新的值)。这样,我们就可以避免阻塞UI线程并保持输入字段的响应性。

何时使用useDeferredValue?

在你的UI的某些部分依赖于频繁更改的值,并导致昂贵的计算或网络请求的情况下,useDeferredValue可能会很有用。例如:

  • 显示过时内容,同时加载新内容。你可以使用useDeferredValue在从API获取新版本的某些数据时显示旧版本的数据。这可以防止显示加载旋转器或回退,并使你的应用程序感觉更快。
  • 指示内容已过时。你可以使用useDeferredValue来显示一些视觉提示,指示某些数据已过时并需要刷新。例如,你可以显示一个灰色文本或一个图标,表示从延迟值派生的某些内容。
  • 延迟重新渲染UI的一部分。你可以使用useDeferredValue来延迟更新用户不重要或不可见的UI的某些部分。例如,你可以延迟更新某些隐藏在选项卡或手风琴后面的图表或图形。

useDeferredValue的最佳实践

在使用useDeferredValue时需要注意一些注意事项和最佳实践。

  • 传递给useDeferredValue的值应该是原始值(例如字符串和数字)或在渲染之外创建的对象。如果你在渲染期间创建一个新对象并立即将其传递给useDeferredValue,它将在每次重新渲染时都不同,导致不必要的后台重新渲染。
  • useDeferredValue本身并不会防止额外的网络请求。你仍然应该根据用户输入进行防抖或节流,并在不再相关时取消任何待处理的请求。
  • useDeferredValue本身没有固定的延迟。一旦React完成原始重新渲染,React将立即开始处理具有新延迟值的后台重新渲染。任何由事件(例如打字)引起的更新都将中断后台重新渲染并优先处理它们。
  • useDeferredValue引起的后台重新渲染直到提交到屏幕时才会触发效果。如果后台重新渲染挂起,则它的效果将在数据加载并UI更新后运行。
  • useDeferredValue&lt;Suspense&gt;集成。如果由新值引起的后台更新挂起UI,则用户将看不到回退。他们将看到旧的延迟值,直到数据加载。# 结论

useDeferredValue是一个强大的钩子,可以通过延迟更新UI的一部分来帮助你优化React性能。它可以在新内容加载时显示旧内容,避免不流畅的UI过渡,从而改善用户体验。但是,你也应该了解它的注意事项和最佳实践,以正确使用它。

了解更多

📁 React的6种最佳文件夹结构:终极比较

⚛️ React服务器组件:构建React应用的新方法

使用JavaScript构建GPT、LangChain的个人助理

译自:https://itnext.io/best-practices-react-usedeferredvalue-to-improve-performance-7b67a08940b9

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
一个人玩
先找到想要的,然后出发

评论(0)

添加评论