- ReactJS 菜鸟教程
- ReactJS 教程
- ReactJS - 简介
- ReactJS - 安装
- ReactJS - 特性
- ReactJS - 优点和缺点
- ReactJS - 架构
- ReactJS - 创建 React 应用程序
- ReactJS - JSX
- ReactJS - 组件
- ReactJS - 嵌套组件
- ReactJS - 使用组件
- ReactJS - 组件集合
- ReactJS - 样式
- ReactJS - 属性(props)
- ReactJS - 使用属性创建组件
- ReactJS - props 验证
- ReactJS - 构造函数
- ReactJS - 组件生命周期
- ReactJS - 事件管理
- ReactJS - 创建事件感知组件
- ReactJS - 在Expense Manager APP中引入事件
- ReactJS - 状态管理
- ReactJS - 状态管理 API
- ReactJS - 无状态组件
- ReactJS - 使用 React Hooks 进行状态管理
- ReactJS - 使用 React 钩子的组件生命周期
- ReactJS - 组件的布局
- ReactJS - 分页
- ReactJS - Material 用户界面
- ReactJS - Http 客户端编程
- ReactJS - 表单编程
- ReactJS - 受控组件
- ReactJS - 不受控制的组件
- ReactJS - Formik
- ReactJS - 条件渲染
- ReactJS - 列表
- ReactJS - 键
- ReactJS - 路由
- ReactJS - 冗余
- ReactJS - 动画
- ReactJS - 引导程序
- ReactJS - 地图
- ReactJS - 表格
- ReactJS - 使用 Flux 管理状态
- ReactJS - 测试
- ReactJS - CLI 命令
- ReactJS - 构建和部署
- ReactJS - 示例
- ReactJS - 钩子简介
- ReactJS - 使用 useState
- ReactJS - 使用 useEffect
- ReactJS - 使用 useContext
- ReactJS - 使用 useRef
- ReactJS - 使用 useReducer
- ReactJS - 使用 useCallback
- ReactJS - 使用 useMemo
- ReactJS - 自定义钩子
- ReactJS - 可访问性
- ReactJS - 代码拆分
- ReactJS - 上下文
- ReactJS - 错误边界
- ReactJS - 转发引用
- ReactJS - 片段
- ReactJS - 高阶组件
- ReactJS - 与其他库集成
- ReactJS - 优化性能
- ReactJS - 分析器 API
- ReactJS - 门户
- ReactJS - 没有 ES6 ECMAScript 的 React
- ReactJS - 没有 JSX 的 React
- ReactJS - 协调
- ReactJS - 引用和 DOM
- ReactJS - 渲染属性
- ReactJS - 静态类型检查
- ReactJS - 严格模式
- ReactJS - Web 组件
- ReactJS - 日期选择器
- ReactJS - Helmet
- ReactJS - 内联样式
- ReactJS - 属性类型
- ReactJS - 浏览器路由器
- ReactJS - DOM
- ReactJS - 旋转木马
- ReactJS - 图标
- ReactJS - 表单组件
- ReactJS - 参考 API
ReactJS - useDeferredValue 钩子
React 18 的版本包含许多新的 React 钩子,这些钩子有助于并发和渲染慢速内容。useDeferredValue 钩子是那些简单易用但难以理解的钩子之一。在本教程中,我们将了解这个钩子是如何工作的,以便我们知道如何以及何时使用它。
useDeferredValue 钩子的工作
在 React 中,useDeferredValue 钩子用于与并发模式交互。并发模式是一个实验性的 React 功能,它允许我们安排和优先处理渲染更新,以创建响应速度更快、更动态的用户界面。
useDeferredValue 通常用于在需要时延迟某些值的处理。这有助于最大限度地减少在给定渲染周期内完成的工作量,并提高应用程序的性能。当我们的值不是立即需要时,例如网络查询或大型计算,此钩子非常有用。
我们可以在组件的顶层调用“useDeferredValue”来获取值的延迟版本。
语法
const deferredValue = useDeferredValue(value);
参数
- value − 这是我们想要推迟的值。它通常是一段数据或一个变量,不能立即需要,或者可以在以后处理。
返回值
返回的延迟值将与我们在原始渲染期间给出的值相同。在更新过程中,React 将首先尝试使用旧值重新渲染,然后在后台使用新值再次重新渲染。
我们可以通过三种方式使用此钩子。首先,通过延迟用户界面的一部分的重新呈现,其次通过显示内容已变旧,第三,通过在加载新内容时显示旧内容。
例子
因此,我们将讨论使用 useDeferredValue 钩子的这三种方法。
示例 - 推迟用户界面(UI)的一部分的重新渲染
在 React 应用程序中,我们可能会面临这样一种情况,即 UI 的一部分更新缓慢并且无法使其更快。假设我们有一个文本输入字段,每次我们写一个字母时,一个组件(例如图表或长列表)都会刷新或重新呈现。这种频繁的重新渲染可能会减慢我们的应用程序速度,即使对于像打字这样的简单操作也是如此。
可以使用 useDeferredValue 钩子来避免此缓慢的组件影响 UI 的其余部分。
import React, { useState } from 'react';
import { useDeferredValue } from 'react';
function SlowList({ text }) {
// Slow operation like rendering a long list
const slowListRendering = (text) => {
console.log(`Rendering the list for text: ${text}`);
setTimeout(() => {
console.log('List rendering complete.');
}, 1000);
};
slowListRendering(text);
return (
<div>
<p>This is a slow component.</p>
{/* Render a chart here */}
</div>
);
}
function App() {
const [text, setText] = useState('');
const deferredText = useDeferredValue(text); // Defer the text input value
return (
<>
<input value={text} onChange={(e) => setText(e.target.value)} />
<SlowList text={deferredText} /> {/* Pass the deferred value */}
</>
);
}
export default App;
输出
示例 - 显示内容已过时
使用 useDeferredValue 时,必须显示内容是旧的,以便告知用户由于延迟,数据不能是最新的。
在下面的示例中,isStale 变量是通过将 deferredData 与当前数据进行比较来计算的。如果它们不匹配,则表示材料已过期,并且 UI 会显示“正在更新...”消息,让用户知道数据正在更新。使用 useDeferredValue 时,这是提供有关数据过期性反馈的简单方法。
import React, { useState } from 'react';
import { useDeferredValue } from 'react';
function MyComponent({ deferredData }) {
// Slow operation
function slowOperation(data) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`Processed data: ${data}`);
}, 2000);
});
}
const [data, setData] = useState('Initial data'); // Initialize data
const isStale = deferredData !== data;
if (isStale) {
// Data is old, simulate loading
slowOperation(deferredData).then((result) => {
setData(result); // Update data when it's no longer old
});
}
return (
<div>
<p>Data: {data}</p>
{isStale && <p>Updating...</p>}
</div>
);
}
function App() {
const [inputData, setInputData] = useState('');
const deferredInputData = useDeferredValue(inputData);
return (
<div>
<input
type="text"
value={inputData}
onChange={(e) => setInputData(e.target.value)}
/>
<MyComponent deferredData={deferredInputData} />
</div>
);
}
export default App;
输出
示例 - 在加载新内容时显示旧内容
我们可以使用 useDeferredValue 来保留旧数据状态和新数据状态,并根据数据的陈旧程度有条件地呈现它们,以便在加载新内容时显示旧内容。下面是一个示例来演示 -
data.js
let cache = new Map();
export function fetchData(url) {
if (!cache.has(url)) {
cache.set(url, getData(url));
}
return cache.get(url);
}
async function getData(url) {
if (url.startsWith("/search?q=")) {
return await getSearchResults(url.slice("/search?q=".length));
} else {
throw Error("Not Found");
}
}
async function getSearchResults(query) {
// Delay to make waiting
await new Promise((resolve) => {
setTimeout(resolve, 400);
});
const allData = [
{
id: 1,
title: "ABC",
year: 2000
},
{
id: 2,
title: "DEF",
year: 2001
},
{
id: 3,
title: "GHI",
year: 2002
},
{
id: 4,
title: "JKL",
year: 2003
},
{
id: 5,
title: "MNO",
year: 2004
},
{
id: 6,
title: "PQR",
year: 2005
},
{
id: 7,
title: "STU",
year: 2006
},
{
id: 8,
title: "VWX",
year: 2007
},
{
id: 9,
title: "YZ",
year: 2008
}
];
const lowerQuery = query.trim().toLowerCase();
return allData.filter((data) => {
const lowerTitle = data.title.toLowerCase();
return (
lowerTitle.startsWith(lowerQuery) ||
lowerTitle.indexOf(" " + lowerQuery) !== -1
);
});
}
SearchData.js
import { fetchData } from "./data.js";
export default function SearchData({ query }) {
if (query === "") {
return null;
}
const myData = use(fetchData(`/search?q=${query}`));
if (myData.length === 0) {
return (
<p>
No data found for <i>"{query}"</i>
</p>
);
}
return (
<ul>
{myData.map((data) => (
<li key={data.id}>
{data.title} ({data.year})
</li>
))}
</ul>
);
}
function use(promise) {
if (promise.status === "fulfilled") {
return promise.value;
} else if (promise.status === "rejected") {
throw promise.reason;
} else if (promise.status === "pending") {
throw promise;
} else {
promise.status = "pending";
promise.then(
(result) => {
promise.status = "fulfilled";
promise.value = result;
},
(reason) => {
promise.status = "rejected";
promise.reason = reason;
}
);
throw promise;
}
}
App.js
import { Suspense, useState } from 'react';
import SearchData from './SearchData.js';
export default function App() {
const [query, setQuery] = useState('');
return (
<>
<label>
Search for the Data here:
<input value={query} onChange={e => setQuery(e.target.value)} />
</label>
<Suspense fallback={<h2>Data is Loading...</h2>}>
<SearchData query={query} />
</Suspense>
</>
);
}
输出
局限性
在 React 中,useDeferredValue 钩子有一些限制,可以用几句话来定义 -
- 一些较旧的 Web 浏览器可能不完全支持 useDeferredValue 钩子。因此,如果我们需要支持过时的浏览器,我们可能会遇到困难。
- 在处理多个延迟值时,使用 useDeferredValue 可能会使我们的代码复杂化。这种额外的复杂性会使我们的代码更难理解和维护。
- 虽然 useDeferredValue 可以帮助提高性能,但它并不是解决所有性能问题的最佳解决方案。我们仍然需要考虑其他性能优化,如代码拆分和服务器端渲染,以获得更好的结果。
- 如果开发人员是 React 的新手,可能需要努力和一些时间来理解 useDeferredValue 钩子。