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 事件 ReactJS 状态管理 ReactJS 状态管理 API ReactJS 无状态组件 ReactJS Hooks 进行状态管理 ReactJS Hooks 的组件生命周期 ReactJS 布局组件 ReactJS 分页 ReactJS Material UI ReactJS Http 客户端编程 ReactJS 表单编程 ReactJS 受控组件 ReactJS 非受控组件 ReactJS Formik ReactJS 条件渲染 ReactJS 列表 ReactJS Key 键 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 上下文 ReactJS 错误边界 ReactJS 转发 Refs ReactJS 片段 ReactJS 高阶组件 ReactJS 与其他库集成 ReactJS 优化性能 ReactJS Profiler API ReactJS Portals ReactJS 不使用 ES6 ECMAScript ReactJS 不使用 JSX 的 React ReactJS Reconciliation ReactJS Refs 和 DOM ReactJS 渲染道具 ReactJS 静态类型检查 ReactJS 严格模式 ReactJS Web 组件

其他概念

ReactJS 日期选择器 ReactJS Helmet ReactJS 内联样式 ReactJS PropTypes ReactJS BrowserRouter ReactJS DOM ReactJS 轮播 ReactJS 图标 ReactJS 表单组件 ReactJS 参考 API

ReactJS 有用资源

ReactJS 快速指南 ReactJS 备忘录 Axios 备忘录 ReactJS 有用资源 ReactJS 讨论


ReactJS - useDeferredValue Hook

React 18 版本包含许多新的 React hooks,它们有助于并发和渲染缓慢的内容。 useDeferredValue hook 是那些使用简单但难以理解的 hooks 之一。在本教程中,我们将了解此 hook 的工作原理,以便我们知道如何以及何时使用它。

useDeferredValue hook 的工作原理

在 React 中,useDeferredValue hook 用于与并发模式交互。并发模式是一项实验性的 React 功能,它允许我们安排和优先处理渲染更新,以创建响应更快、更动态的用户界面。

useDeferredValue 通常用于在需要某些值时推迟处理它们。这有助于最大限度地减少给定渲染周期内完成的工作量并提高应用程序的性能。当我们拥有一些不立即需要的值(例如网络查询或大型计算)时,此Hooks(钩子)非常有用。

我们可以在组件的顶层调用"useDeferredValue"来获取值的延迟版本。

语法

const deferredValue = useDeferredValue(value);

参数

value − 它是我们想要延迟的值。它通常是一段数据或一个变量,不能立即需要,或者可以稍后处理。

返回值

返回的延迟值将与我们在原始渲染期间给出的值相同。在更新期间,React 将首先尝试使用旧值重新渲染,然后使用新值在后台再次重新渲染。

我们可以通过三种方式使用此Hooks(钩子)。首先,推迟重新渲染部分用户界面,其次,显示内容已变旧,第三,在加载新内容时显示旧内容。

示例

因此,我们将讨论使用 useDeferredValue Hooks(钩子)的所有这三种方式。

示例 − 推迟重新渲染部分用户界面 (UI)

在 React 应用程序中,我们可能会遇到这样一种情况,即我们的 UI 的一部分更新缓慢且无法加快速度。假设我们有一个文本输入字段,每次我们写一个字母时,组件(例如图表或长列表)都会刷新或重新渲染。这种频繁的重新渲染可能会减慢我们的应用速度,即使是像输入这样的简单操作也是如此。

可以使用 useDeferredValue Hooks(钩子)来避免这个缓慢的组件影响 UI 的其余部分。

import React, { useState } from 'react';
import { useDeferredValue } from 'react';

function SlowList({ text }) {
   
   // 操作缓慢,例如渲染长列表
   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); // 延迟文本输入值
   
   return (
      <>
         <input value={text} onChange={(e) => setText(e.target.value)} />
         <SlowList text={deferredText} /> {/* Pass the deferred value */}
      </>
   );
}
export default App;

输出

slow component

示例 − 显示内容已过时

使用 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'); // 初始化数据
   const isStale = deferredData !== data;
   
   if (isStale) {
   
      // 数据较旧,模拟加载
      slowOperation(deferredData).then((result) => {
         setData(result); // 当数据不再过时时更新数据
      });
   }
   
   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;

输出

initial data

示例 − 在加载新内容时显示旧内容

我们可以使用 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) {

   // 延迟等待
   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>
      </>
   );
}

输出

search for data

限制

在 React 中,useDeferredValue Hooks(钩子)有一些限制,可以用几个词来定义 −

  • 一些较旧的 Web 浏览器可能不完全支持 useDeferredValue Hooks(钩子)。因此,如果我们需要支持过时的浏览器,我们可能会遇到困难。

  • 在处理多个延迟值时,使用 useDeferredValue 可能会使我们的代码复杂化。这种额外的复杂性会使我们的代码更难理解和维护。

  • 虽然 useDeferredValue 可以帮助提高性能,但它并不是所有性能问题的最佳解决方案。为了获得更好的结果,我们仍然需要考虑其他性能优化,如代码拆分和服务端渲染。

  • 如果开发人员是 React 新手,可能需要花费一些时间和精力来理解 useDeferredValue Hooks(钩子)。

reactjs_reference_api.html