原文地址:《Snappy UI Optimization with useDeferredValue》 - 使用 useDeferredValue 进行快速UI优化

NOTE

  • 指定低优先级,延迟更新
  • 使用 useDeferredValue 时,子组件需要 memo
  • useDeferredValue 的值并不一定必须是state
  • 使用 useDeferredValue 可以获取UI更新中的状态,可以像用户明确展示UI发生变化,正在更新
  • React 19 中 useDeferredValue 可以指定一个默认值,加快初始渲染速度

这篇文章的标题是《使用 useDeferredValue 优化 UI 性能》,作者 Josh W. Comeau 讨论了 React 中一个强大但鲜为人知的工具:useDeferredValue。这个钩子可以在特定情况下对用户体验产生巨大的影响。

引言

作者介绍了 useDeferredValue,并分享了如何使用它来修复他的博客上的一个性能问题。他发现在低端设备上的性能提升感觉像在使用黑魔法。

问题

文章通过作者之前发布的一个工具——Shadow Palette Generator(阴影调色板生成器)来说明问题。这个工具允许用户通过滑动滑块和其他控件来设计自己的阴影集,并将 CSS 代码提供给用户复制粘贴到他们自己的应用中。

问题在于,UI 中的控件旨在提供即时反馈,即当用户拖动滑块时,UI 会每秒重新渲染数十次。对于大多数设备来说,浏览器无法足够快地完成这些操作,导致界面变得卡顿。

不完美的解决方案

作者最初使用“节流”技术来解决这个问题,将组件的重新渲染限制为每200毫秒一次。虽然这比之前更好,但仍然不完美。它给用户一种延迟的感觉,而且不考虑不同设备的性能差异。

介绍 useDeferredValue

useDeferredValue 是一个 React 钩子,允许我们将 UI 分为高优先级和低优先级区域。它的工作原理是允许 React 在重要事件发生时中断自身。

示例

作者通过一个简单的例子来解释 useDeferredValue 的工作原理。在这个例子中,有一个名为 count 的状态变量,可以通过点击按钮来递增。ImportantStuff 代表 UI 的高优先级部分,我们希望它在 count 变化时立即更新。SlowStuff 代表 UI 的低优先级部分。

工作原理

count 状态变化时,App 组件会立即重新渲染,但 deferredCount(由 useDeferredValue 提供)并没有改变,仍然是之前的值。这意味着 SlowStuff 接收到的属性与上一次渲染时完全相同。如果它使用了 React.memo() 进行了记忆化,它就不会重新渲染,因为 React 已经知道将产生什么内容。

注意事项

  • useDeferredValue 仅在慢速/低优先级组件被 React.memo() 包装时才有效。
  • 与多个状态变量一起使用 useDeferredValue 时,可以推迟派生值的渲染,例如在渲染期间生成的 CSS 代码块。

加载指示

在某些情况下,我们可能希望向用户明确指出 UI 的某些部分已经过时,以便他们知道正在进行重新计算。

初始渲染加速

React 19 的 beta 版本为 useDeferredValue 带来了一个新的能力:可以指定一个初始值。这将允许我们潜在地加速初始渲染。

结果

作者展示了使用 useDeferredValue 钩子后的最终结果:一切都非常流畅。即使是在低端设备上,性能也有了显著提升。

结论

useDeferredValue 可能看起来复杂,但如果你有正确的思维模型,它实际上并不可怕。作者通过这篇文章帮助读者理解了 useDeferredValue 的工作原理,并展示了如何使用它来显著提高应用程序的性能。