概述
想必我们在项目中可能使用过Suspense
组件,这个组件当其子组件数据未准备好之前会显示占位符内容(后备方案),更加注重用户体验,一般场景就是当我们使用懒加载、异步请求数据会通过该组件添加loading
效果。而useDeferredValue
则是更加关注渲染性能,在数据未加载之前会返回旧值,并结合memo
来减少不必要的渲染,如果不使用memo
则优化无效。本文继续通过基本使用和源码来深入学习useDeferredValue
的原理
基本使用
useDeferredValue
是一个 React Hook,可以让你延迟更新 UI 的某些部分。接收两个参数,并返回旧值:
value
: 想延迟的值,可以是任何类型。initialValue
:仅 Canary 可选 initialValue :在组件初始渲染期间使用的值。如果省略此选项, useDeferredValue 则不会在初始渲染期间延迟,因为它没有可以渲染的 value 先前版本。currentValue
(返回值):在初始渲染期间,返回的延迟值将与您提供的值相同。在更新过程中,React 将首先尝试使用旧值重新渲染(因此它将返回旧值),然后在后台尝试使用新值进行另一次重新渲染(因此它将返回更新的值)。
React版本说明:
- Canary:频繁发布,实验性功能,快速迭代和反馈,不推荐用于生产环境。
- Alpha:早期测试版本,新功能和改进,功能不够稳定。
- Beta:功能基本完成,有一些 bug,用于广泛测试和反馈。
- RC:功能完成,经过广泛测试,主要用于发现和修复小问题,接近最终版本。
- Stable:最终发布的稳定版本,适用于生产环境,功能稳定可靠
进度链可以这样理解: Canary - Alpha - Beta - RC - Stable(生产环境)
我们都是基于生产环境介绍,所以会省略initialValue参数的说明。
官网Demo:
export default function App() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
return (
<>
<label>
Search albums:
<input value={
query} onChange={
e => setQuery(e.target.value)} />
</label>
<Suspense fallback={
<h2>Loading...</h2>}>
<SearchResults query={
deferredQuery} />
</Suspense>
</>
);
}
在代码中我们使用到了Suspense
和SearchResults
,在上面的示例中,输入 “a”,等待结果加载完成,然后将输入框编辑为 “ab”。输入框input
值会立即更新,但是SearchResults
组件的内容会延迟更新。注意,现在你看到的不是 suspense 后备方案,而是旧的结果列表,直到新的结果加载完成。这是因为suspense是在数据未加载之前显示后备方案,而useDeferredValue在数据未加载之前会返回旧值并且降低更新优先级,此时在suspense看来值已经加载完了只不过是旧值,所以不会显示后备方案。
两者区别如下:
Suspense 注重用户体验,处理异步数据或组件加载时的加载状态,提供优雅的占位符
。useDeferredValue 注重渲染性能,通过延迟低优先级更新保持界面的高响应性,避免界面卡顿。
需要注意的是:
Suspense
和useDeferredValue
同时使用时,u