【React】 Hooks useTransition 解析與性能優化實踐

1.背景

  1. useTransition 是 React 18 引入的一個并發模式下的 Hook,用于區分緊急和非緊急的狀態更新,提升應用的響應性和用戶體驗;
  2. 它可以管理 UI 中的過渡狀態,特別是在處理長時間運行的狀態更新時。
  3. 它允許你將某些更新標記為“過渡”狀態,這樣 React 可以優先處理更重要的更新,比如用戶輸入,同時延遲處理過渡更新。
  4. 以下是其核心要點、使用場景和注意事項:

2.核心功能

  1. 標記過渡狀態:將非緊急的狀態更新標記為“過渡”(Transition),允許 React 延遲處理這些更新,優先處理高優先級任務(如用戶交互)。
  2. 保持 UI 響應:在狀態轉換期間,組件仍能保持響應,避免界面卡頓。
  3. 提供加載狀態:通過 isPending 指示過渡任務是否正在進行,可配合加載指示器(如 Spinner)提升用戶體驗。

3.基本用法

3.1 eg:

import { useTransition } from 'react';function MyComponent() {const [isPending, startTransition] = useTransition();const [count, setCount] = useState(0);const handleClick = () => {startTransition(() => {setCount(c => c + 1); // 標記為過渡更新});};return (<div>{isPending && <Spinner />} {/* 顯示加載指示器 */}<button onClick={handleClick}>Increment</button><p>Count: {count}</p></div>);
}

3.1 參數

useTransition 不需要任何參數

3.2 返回值

useTransition 返回一個數組 包含兩個元素[isPending, startTransition]

  1. isPending:布爾值,表示過渡任務是否正在進行。
  2. startTransition:函數,用于包裹低優先級的狀態更新。

4、使用場景

4.1 大量數據渲染

例如,過濾或排序大型列表時,避免界面卡頓。

function DataGrid() {const [data, setData] = useState([]);const [isPending, startTransition] = useTransition();const [filter, setFilter] = useState('');const handleFilterChange = (newFilter) => {setFilter(newFilter);startTransition(() => {const filteredData = processLargeDataSet(newFilter);setData(filteredData);});};return (<div><input value={filter} onChange={e => handleFilterChange(e.target.value)} />{isPending ? <LoadingGrid /> : <VirtualizedGrid data={data} />}</div>);
}

4.2 路由切換

預加載下一頁數據時保持當前頁響應。

function App() {const [isPending, startTransition] = useTransition();const [currentPage, setCurrentPage] = useState('home');const navigate = (page) => {startTransition(() => {setCurrentPage(page);});};return (<div><Navigation onNavigate={navigate} />{isPending ? <PageTransitionSpinner /> : <Page name={currentPage} />}</div>);
}

4.3 表單驗證

實時響應用戶輸入,同時延遲更新驗證結果。

function ComplexForm() {const [formData, setFormData] = useState({});const [errors, setErrors] = useState({});const [isPending, startTransition] = useTransition();const handleChange = (e) => {const { name, value } = e.target;setFormData(prev => ({ ...prev, [name]: value }));startTransition(() => {const validationErrors = validateFormField(name, value);setErrors(prev => ({ ...prev, [name]: validationErrors }));});};return (<form><input name="email" onChange={handleChange} value={formData.email || ''} />{isPending ? <ValidatingIndicator /> : (errors.email && <ErrorMessage error={errors.email} />)}</form>);
}

4.4 搜索或篩選功能

實時響應用戶輸入,同時延遲更新結果展示。

function SearchResults() {const [query, setQuery] = useState('');const [results, setResults] = useState([]);const [isPending, startTransition] = useTransition();const handleSearch = (e) => {setQuery(e.target.value);startTransition(() => {const searchResults = performSearch(e.target.value);setResults(searchResults);});};return (<div><input value={query} onChange={handleSearch} />{isPending ? <div>Loading...</div> : (<ul>{results.map(result => (<li key={result.id}>{result.title}</li>))}</ul>)}</div>);
}

5. 場景模擬

創建了一個簡單的輸入框和一個列表,用于展示基于輸入關鍵詞的結果。

mockjs文檔地址:https://github.com/nuysoft/Mock/wiki/Getting-Started

5.1 安裝使用到的插件

pnpm add mockjs antd 
pnpm add -D @types/mockjs @type/node

package.json

{...."dependencies": {"antd": "^5.24.9","mockjs": "^1.1.0","react": "^19.0.0","react-dom": "^19.0.0"},"devDependencies": {"@types/mockjs": "^1.0.10","@types/node": "^22.15.3","@types/react": "^19.1.2",.....}
}

5.2 編寫 vite.config.ts

結合 vite插件實現一個api, 這個api可以幫助我們模擬數據。

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import type { Plugin } from 'vite'
import mockjs from 'mockjs'
// 使用 URL 模塊解析 URL
import url from 'node:url'/*** 創建一個 Vite Mock 服務器插件* @returns Vite 插件實例*/
const viteMockServer = (): Plugin => {return {// 插件名稱name: 'vite-plugin-mock',// 配置開發服務器configureServer(server) {// 添加中間件處理 mock 請求server.middlewares.use('/api/mock/list', (req, res) => {// 解析請求 URL 中的查詢參數const parseurl = url.parse(req.originalUrl ?? '', true).query;// 設置響應頭為 JSON 格式res.setHeader('Content-Type', 'application/json');// 使用 mockjs 生成模擬數據const data = mockjs.mock({'list|2000': [{id: '@guid',// name: '@cword(2, 4)',name: parseurl.key,age: '@integer(18, 30)',address: '@county(true)',},],});// 將數據轉換為 JSON 字符串并發送響應res.end(JSON.stringify(data));})}}
}// https://vite.dev/config/
export default defineConfig({plugins: [react(), viteMockServer()],
})

編寫完成訪問我們的接口 http://localhost:5174/api/list?keyWord=xx 5174為默認端口,可以自行更改,返回數據如下

{"list": [{"id": "DCe1D11e-8D24-31e6-fE76-5AbAA6cf7E6F","name": "a","age": 25,"address": "西藏自治區 日喀則地區 仲巴縣"},{"id": "EAb5ffb6-b43B-93cC-cDfb-18A7Ce15BFda","name": "a","age": 21,"address": "安徽省 馬鞍山市 花山區"}.......]
}

5.3 業務組件編寫

App.tsx

  1. 輸入框和狀態管理 使用 useState Hook 管理輸入框的值和結果列表。 每次輸入框的內容變化時,handleInputChange 函數會被觸發,它會獲取用戶輸入的值,并進行 API 請求。
  2. API 請求 在 handleInputChange 中,輸入的值會作為查詢參數發送到 /api/list API。API 返回的數據用于更新結果列表。 為了優化用戶體驗,我們將結果更新放在 startTransition 函數中,這樣 React 可以在處理更新時保持輸入框的響應性。
  3. 使用 useTransition useTransition 返回一個布爾值 isPending,指示過渡任務是否仍在進行中。 當用戶輸入時,如果正在加載數據,我們會顯示一個簡單的“loading…”提示,以告知用戶當前操作仍在進行。
  4. 列表渲染 使用 List 組件展示返回的結果,列表項顯示每個結果的 name 和 address。
// 使用 React 和 Ant Design 組件實現一個模擬帶搜索功能的列表
import { Input, List, Spin } from 'antd'
import { useState, useTransition, useCallback } from 'react'interface ListItem {id: string;name: string;address: string;age: number;
}function App() {const [list, setList] = useState<ListItem[]>([]);const [inputValue, setInputValue] = useState('');const [isPending, startTransition] = useTransition();// 處理輸入框變化,使用 useCallback 優化性能const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {const value = e.target.value;setInputValue(value);// 發起請求獲取數據fetch(`/api/mock/list?key=${value}`).then((res) => res.json()).then((res) => {// 使用 startTransition 包裹狀態更新,優化大數據渲染性能startTransition(() => {setList(res.list)});}).catch(err => {console.error('獲取數據失敗:', err);});}, []);return (<><Input placeholder="請輸入搜索關鍵詞"value={inputValue} onChange={handleInputChange} />{isPending ? (<Spin tip="加載中..." />) : (<ListdataSource={list}renderItem={(item) => (<List.Item>{item.address}</List.Item>)}/>)}</>);
}export default App;

5.4 測試使用

為了更好的測試結果可以在性能中降級 cpu 渲染速度

在這里插入圖片描述

6. 注意事項

startTransition必須是同步的

錯誤做法

startTransition(() => {// ? 在調用 startTransition 后更新狀態setTimeout(() => {setPage('/about');}, 1000);
}); 

正確做法

setTimeout(() => {startTransition(() => {// ? 在調用 startTransition 中更新狀態setPage('/about');});
}, 1000);

async await 錯誤做法

startTransition(async () => {await someAsyncFunction();// ? 在調用 startTransition 后更新狀態setPage('/about');
});

正確做法

await someAsyncFunction();
startTransition(() => {// ? 在調用 startTransition 中更新狀態setPage('/about');
});

7. 原理剖析

useTransition 的核心原理是將一部分狀態更新處理為低優先級任務,這樣可以將關鍵的高優先級任務先執行,而低優先級的過渡更新則會稍微延遲處理。這在渲染大量數據、進行復雜運算或處理長時間任務時特別有效。React 通過調度機制來管理優先級:

  1. 高優先級更新:直接影響用戶體驗的任務,比如表單輸入、按鈕點擊等。
  2. 低優先級更新:相對不影響交互的過渡性任務,比如大量數據渲染、動畫等,這些任務可以延遲執行。
  +-----------------------+|         App           ||                       ||  +--------------+     ||  |    Input     |     ||  +--------------+     ||                       ||  +--------------+     ||  |   Display    |     ||  +--------------+     |+-----------------------+用戶輸入|v[高優先級更新] ---> [調度器] ---> [React 更新組件]|+---> [低優先級過渡更新] --> [調度器] --> [等待處理]

8.擴展

useTransition 與防抖的區別?

seTransition與 防抖在前端開發中都是用于優化性能的手段,但它們的核心原理、應用場景和實現方式存在顯著區別,以下是詳細對比:

核心原理對比

  • useTransition
    • 基于React的并發模式(Concurrent Features),通過將狀態更新標記為“過渡”(Transition)實現。
    • 允許React在后臺處理低優先級任務,優先響應高優先級操作(如用戶輸入),從而保持界面流暢。
    • 更新過程可中斷,避免長時間阻塞主線程,提升用戶體驗。
  • 防抖(Debounce)
    • 延遲函數執行,直到事件觸發后的一段時間內沒有再次觸發。
    • 適用于需要等待用戶停止操作后再執行的場景(如搜索輸入、表單驗證)。

應用場景對比

  • useTransition適用場景
    • 大數據列表過濾:當用戶輸入搜索內容時,通過useTransition將篩選任務標記為低優先級,避免阻塞輸入框的實時更新,保持輸入流暢性。
    • 復雜UI更新:在渲染需要消耗大量時間的頁面時,使用useTransition優化視圖切換體驗。
    • 表單提交與篩選器切換:需要延遲渲染的操作(如異步數據加載)中,useTransition可確保用戶交互的即時響應。
  • 防抖適用場景
    • 搜索框輸入檢測:等待用戶停止輸入后再執行搜索,減少無效請求。
    • 手機號和郵箱驗證:在用戶停止輸入后驗證格式,避免實時驗證的性能開銷。
    • 窗口大小變化后的重新渲染:在窗口調整結束后執行布局計算,避免頻繁重繪。

優缺點對比

  • useTransition優點
    • 更新協調過程可中斷,避免長時間阻塞主線程。
    • 用戶操作可及時得到響應,提升交互體驗。
    • 不需要開發者手動配置時間間隔,React自動優化。
  • useTransition缺點
    • 僅適用于React 18及以上版本,且需配合并發模式使用。
    • 對于簡單場景,可能引入不必要的復雜性。
  • 防抖優點
    • 可確保在用戶停止操作后執行函數,減少無效請求。
    • 實現簡單,適用于等待用戶輸入的場景。
  • 防抖缺點
    • 可能導致用戶輸入長時間得不到響應。
    • 無法處理需要即時反饋的操作。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81694.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81694.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81694.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

蘑菇管理——AI與思維模型【94】

一、定義 蘑菇管理思維模型是一種形象地描述組織對待新員工或初入職場者的管理方式及相關現象的思維模型。它將新員工或初入職場者比作蘑菇&#xff0c;這些人在初期往往被置于陰暗的角落&#xff08;不受重視的部門&#xff0c;或打雜跑腿的工作&#xff09;&#xff0c;澆上…

c++STL——set和map的使用

文章目錄 set和map的使用set系列聲名和定義默認成員函數迭代器set的增刪查lower_bound和upper_boundInsert接口pair類 對于查找的另一種使用 set和multiset的區別 map系列聲名和定義pair類的進一步介紹默認成員函數map的增刪查map的數據修改map和multimap的差異 set和map的使用…

什么是DGI數據治理框架?

DGI數據治理框架是由數據治理研究所&#xff08;Data Governance Institute, DGI&#xff09;提出的一套系統性方法論&#xff0c;旨在幫助企業或組織建立有效的數據治理體系&#xff0c;確保數據資產的高質量管理、合規使用和價值釋放。以下是關于DGI數據治理框架的核心內容&a…

chrome 瀏覽器怎么不自動提示是否翻譯網站

每次訪問外國語網頁都會彈出這個對話框&#xff0c;很是麻煩&#xff0c;每次都得手動關閉一下。 不讓他彈出來方法&#xff1a; 設置》語言》首選語言》添加語言&#xff0c;搜索英語添加上 如果需要使用翻譯&#xff0c;就點擊三個點&#xff0c;然后選擇翻譯

LeetCode 熱題 100 54. 螺旋矩陣

LeetCode 熱題 100 | 54. 螺旋矩陣 大家好&#xff0c;今天我們來解決一道經典的算法題——螺旋矩陣。這道題在LeetCode上被標記為中等難度&#xff0c;要求我們按照順時針螺旋順序返回矩陣中的所有元素。下面我將詳細講解解題思路&#xff0c;并附上Python代碼實現。 問題描述…

生成式AI將重塑的未來工作

在人類文明的長河中,技術革命始終是推動社會進步的核心動力。從蒸汽機的轟鳴到互聯網的浪潮,每一次技術躍遷都在重塑著人類的工作方式與生存形態。而今,生成式人工智能(Generative AI)的崛起,正以超越以往任何時代的速度與深度,叩響未來工作范式變革的大門。這場變革并非…

【2025軟考高級架構師】——2024年05月份真題與解析

摘要 本文內容是關于2025年軟考高級架構師考試的相關資料&#xff0c;包含2024年05月份真題與解析。其中涉及體系結構演化的步驟、OSI協議中能提供安全服務的層次、數據庫設計階段中進行關系反規范化的環節等知識點&#xff0c;還提及了軟考高級架構師考試的多個模塊&#xff…

KAG:通過知識增強生成提升專業領域的大型語言模型(三)

目錄 摘要 Abstract 1 Schema 2 Prompt 3 KAG-Builder 3.1 reader 3.2 splitter 3.3 extractor 3.4 vectorizer 3.5 writer 3.6 可選組件 4 示例 總結 摘要 本周深入學習了 KAG 項目中的 Schema、Prompt 以及 KAG-Builder 相關代碼知識&#xff0c;涵蓋了其定義、…

Gitea windows服務注冊,服務啟動、停止、重啟腳本

修改配置文件 查看COMPUTERNAME echo %COMPUTERNAME%進入配置文件D:\gitea\custom\conf\app.ini&#xff0c;將 Gitea 設置為以本地系統用戶運行 如果結果是 USER-PC&#xff0c;那么 RUN_USER USER-PC$ RUN_USER COMPUTERNAME$SQLite3 PATH配置&#xff0c;更改為包含完整…

礦泉水瓶的繪制

1.制作中心矩形&#xff0c;大小為60&#xff0c;注意設置矩形的兩條邊相等 2.點擊拉伸&#xff0c;高度為150mm 3.使用圓角命令&#xff0c;點擊連接到開始面&#xff0c;同時選中4條邊&#xff0c;進行圓角轉化&#xff0c;圓角大小為10mm&#xff0c;點擊多半徑圓角&#xf…

【程序+論文】大規模新能源并網下的火電機組深度調峰經濟調度

目錄 1 主要內容 講解重點 2 講解視頻及代碼 1 主要內容 該視頻為《大規模新能源并網下的火電機組深度調峰經濟調度》代碼講解內容&#xff0c;該程序有完全對照的論文&#xff0c;以改進IEEE30節點作為研究對象&#xff0c;系統包括5個火電機組和2個新能源機組&#xff0c;…

??工業機器人智能編程:從示教器到AI自主決策??

工業機器人智能編程:從示教器到AI自主決策 引言 工業機器人作為智能制造的核心裝備,其編程方式正經歷革命性變革。傳統示教器編程效率低下,平均每個路徑點需要30秒人工示教,而復雜軌跡編程可能耗時數周。隨著AI技術的發展,工業機器人編程正朝著"所見即所得"的…

n8n 構建一個 ReAct AI Agent 示例

n8n 構建一個 ReAct AI Agent 示例 0. 引言1. 詳細步驟創建一個 "When Executed by Another Workflow"創建一個 "Edit Fields (Set)"再創建一個 "Edit Fields (Set)"創建一個 HTTP Request創建一個 If 節點在 true 分支創建一個 "Edit Fiel…

Monorepo項目多項目一次性啟動工具對比與實踐

Monorepo項目多項目一次性啟動工具對比與實踐 在現代軟件開發中&#xff0c;Monorepo&#xff08;單一倉庫&#xff09;模式越來越受到開發者的青睞。Monorepo將多個相關的項目或包集中在一個倉庫中進行管理&#xff0c;方便依賴共享、代碼復用和統一發布。在Monorepo項目開發…

筆記整理六----OSPF協議

OSPF 動態路由的分類&#xff1a; 1.基于網絡范圍進行劃分--將網絡本身劃分為一個個AS&#xff08;自治系統---方便管理和維護&#xff09; 內部網關協議---負責AS內部用戶之間互相訪問使用的協議 IGP--RIP EIGRP ISIS OSPF 外部網關協議--負責AS之間&#xff08;整個互聯網&…

網絡編程,使用select()進行簡單服務端與客戶端通信

這里在Ubuntu環境下演示 一般流程 服務端常用函數&#xff1a; socket()&#xff1a;創建一個新的套接字。bind()&#xff1a;將套接字與特定的IP地址和端口綁定。listen()&#xff1a;使套接字開始監聽傳入的連接請求。accept()&#xff1a;接受一個傳入的連接請求&#xff…

智能決策支持系統的基本概念與理論體系

決策支持系統是管理科學的一個分支&#xff0c;原本與人工智能屬于不同的學科范疇&#xff0c;但自20世紀80年代以來&#xff0c;由于專家系統在許多方面取得了成功&#xff0c;于是人們開始考慮把人工智能技術用于計算機管理中來。在用計算機所進行的各種管理中&#xff0c;如…

驅動開發系列55 - Linux Graphics QXL顯卡驅動代碼分析(二)顯存管理

一:概述 前面介紹了當內核檢測到匹配的PCI設備后,會調用 qxl_pci_probe 初始化設備,其中會調用qxl_device_init 來初始化設備,為QXL設備進行內存映射,資源分配,環形緩沖區初始化,IRQ注冊等操作,本文展開說說這些細節,以及介紹下QXL的顯存管理。 二:QXL設備初始化細節…

洛谷 P1495:【模板】中國剩余定理(CRT)/ 曹沖養豬

【題目來源】 https://www.luogu.com.cn/problem/P1495 https://www.acwing.com/problem/content/225/ 【題目描述】 自從曹沖搞定了大象以后&#xff0c;曹操就開始捉摸讓兒子干些事業&#xff0c;于是派他到中原養豬場養豬。可是曹沖滿不高興&#xff0c;于是在工作中馬馬虎…

配置和使用持久卷

配置和使用持久卷 文章目錄 配置和使用持久卷[toc]一、PV與PVC的持久化存儲機制二、PV和PVC的生命周期三、創建基于NFS的PV1.準備NFS共享目錄2.創建PV 四、基于PVC使用PV1.創建PVC2.使用PVC 五、基于StorageClass實現動態卷制備1.獲取NFS服務器的連接信息2.獲取nfs-subdir-exte…