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