- 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。