- ReactJS 教程
- 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 Hooks 进行组件生命周期管理
- ReactJS - 布局组件
- ReactJS - 分页
- ReactJS - Material UI
- ReactJS - Http 客户端编程
- ReactJS - 表单编程
- ReactJS - 受控组件
- ReactJS - 非受控组件
- ReactJS - Formik
- ReactJS - 条件渲染
- ReactJS - 列表
- ReactJS - Keys
- ReactJS - 路由
- ReactJS - Redux
- ReactJS - 动画
- ReactJS - Bootstrap
- ReactJS - Map
- ReactJS - 表格
- ReactJS - 使用 Flux 管理状态
- ReactJS - 测试
- ReactJS - CLI 命令
- ReactJS - 构建和部署
- ReactJS - 示例
- Hooks
- ReactJS - Hooks 简介
- ReactJS - 使用 useState
- ReactJS - 使用 useEffect
- ReactJS - 使用 useContext
- ReactJS - 使用 useRef
- ReactJS - 使用 useReducer
- ReactJS - 使用 useCallback
- ReactJS - 使用 useMemo
- ReactJS - 自定义 Hooks
- ReactJS 高级
- ReactJS - 可访问性
- ReactJS - 代码分割
- ReactJS - Context
- ReactJS - 错误边界
- ReactJS - 转发 Refs
- ReactJS - 片段
- ReactJS - 高阶组件
- ReactJS - 与其他库集成
- ReactJS - 性能优化
- ReactJS - Profiler API
- ReactJS - Portals
- ReactJS - 无 ES6 ECMAScript 的 React
- ReactJS - 无 JSX 的 React
- ReactJS - 调和
- ReactJS - Refs 和 DOM
- ReactJS - 渲染 Props
- ReactJS - 静态类型检查
- ReactJS - Strict Mode
- ReactJS - Web Components
- 其他概念
- ReactJS - 日期选择器
- ReactJS - Helmet
- ReactJS - 内联样式
- ReactJS - PropTypes
- ReactJS - BrowserRouter
- ReactJS - DOM
- ReactJS - 走马灯
- ReactJS - 图标
- ReactJS - 表单组件
- ReactJS - 参考 API
- ReactJS 有用资源
- ReactJS - 快速指南
- ReactJS - 有用资源
- ReactJS - 讨论
ReactJS - useDeferredValue 钩子
React 18 版本包含许多新的 React hook,有助于并发和渲染缓慢的内容。useDeferredValue hook 就是其中一个易于使用但难以理解的 hook。在本教程中,我们将了解此 hook 的工作原理,以便我们知道如何以及何时使用它。
useDeferredValue hook 的工作原理
在 React 中,useDeferredValue hook 用于与并发模式交互。并发模式是 React 的一个实验性功能,允许我们调度和优先处理渲染更新,以创建更具响应性和动态性的用户界面。
useDeferredValue 通常用于推迟处理某些值的时机。这有助于最大限度地减少给定渲染周期中完成的工作量,并提高应用程序的性能。当我们拥有不需要立即处理的值时,例如网络查询或大型计算,此 hook 非常有用。
我们可以在组件的顶层调用“useDeferredValue”以获取值的延迟版本。
语法
const deferredValue = useDeferredValue(value);
参数
value − 这是我们想要推迟的值。它通常是一段数据或一个变量,可能不需要立即使用或可以在稍后处理。
返回值
返回的延迟值将与我们在原始渲染期间提供的值相同。在更新期间,React 将首先尝试使用旧值重新渲染,然后在后台使用新值进行另一次重新渲染。
我们可以通过三种方式使用此 hook。首先是推迟用户界面一部分的重新渲染,其次是显示内容已过期,第三是显示旧内容,同时加载新内容。
示例
因此,我们将讨论使用 useDeferredValue hook 的这三种方式。
示例 - 推迟用户界面 (UI) 部分的重新渲染
在 React 应用程序中,我们可能会遇到 UI 的一部分更新缓慢且无法使其更快的情况。假设我们有一个文本输入字段,并且每次我们写入一个字母时,一个组件(例如图表或长列表)都会刷新或重新渲染。这种频繁的重新渲染可能会减慢我们的应用程序速度,即使对于像打字这样的简单操作也是如此。
可以使用 useDeferredValue hook 来避免此缓慢的组件影响 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 变量是通过比较延迟数据与当前数据来计算的。如果它们不匹配,则表示材料已过期,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 hook 有一些限制,可以用几句话来概括:
一些较旧的网络浏览器可能无法完全支持 useDeferredValue hook。因此,如果我们需要支持过时的浏览器,我们可能会遇到困难。
处理多个延迟值时,使用 useDeferredValue 可能会使我们的代码复杂化。这种额外的复杂性会使我们的代码更难以理解和维护。
虽然 useDeferredValue 可以帮助提高性能,但它并不是所有性能问题的最佳解决方案。我们仍然需要考虑其他性能优化,例如代码分割和服务器端渲染,以获得更好的结果。
如果开发人员不熟悉 React,则可能需要付出努力和一些时间才能理解 useDeferredValue hook。