React Hooks 完全指南:從基礎到高級的實戰技巧

概述

React Hooks 是 React 16.8 引入的新特性,允許在函數組件中使用狀態和其他 React 特性。根據數據的使用場景和更新機制,可以將 Hooks 分為三大類:

1. 保存只讀數據

useMemo

用途:?緩存計算結果,避免重復計算

語法:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

特點:

  • 只有當依賴項發生變化時才重新計算
  • 適用于計算量大的操作
  • 返回緩存的值

使用場景:

// 復雜計算
const expensiveValue = useMemo(() => {return items.filter((item) => item.price > 100).map((item) => ({...item,discount: item.price * 0.1,}));
}, [items]);// 對象/數組緩存
const memoizedObject = useMemo(() => ({id: user.id,name: user.name,avatar: user.avatar,}),

[user.id, user.name, user.avatar]

);

useCallback

用途:?緩存函數,避免子組件不必要的重新渲染

語法:

const memoizedCallback = useCallback(() => {doSomething(a, b);
}, [a, b]);

特點:

  • 只有當依賴項變化時才創建新的函數
  • 主要用于性能優化
  • 返回緩存的函數引用

使用場景:

// 傳遞給子組件的回調函數
const handleClick = useCallback((id) => {setSelectedId(id);fetchUserDetails(id);
}, []);// 事件處理函數
const handleSubmit = useCallback((formData) => {submitForm(formData);},[submitForm]
);// 子組件優化
const ChildComponent = React.memo(({ onUpdate }) => {return <button onClick={onUpdate}>更新</button>;
});

2. 保存可變數據,更改時觸發渲染

useState

用途:?管理組件內的簡單狀態

語法:

const [state, setState] = useState(initialState);

特點:

  • 狀態更新會觸發組件重新渲染
  • 異步更新,多個 setState 會被批處理
  • 適合簡單的狀態管理

使用場景:

// 基礎狀態管理
const [count, setCount] = useState(0);
const [name, setName] = useState("");
const [isLoading, setIsLoading] = useState(false);// 對象狀態
const [user, setUser] = useState({name: "",email: "",age: 0,
});// 函數式更新
setCount((prevCount) => prevCount + 1);
setUser((prevUser) => ({...prevUser,name: "新名字",
}));

useReducer

用途:?管理復雜的狀態邏輯

語法:

const [state, dispatch] = useReducer(reducer, initialState, init);

特點:

  • 狀態更新邏輯集中管理
  • 適合復雜的狀態轉換
  • 可以處理多個相關的狀態

使用場景:

// 定義 reducer
const todoReducer = (state, action) => {switch (action.type) {case "ADD_TODO":return {...state,todos: [...state.todos, action.payload],};case "TOGGLE_TODO":return {...state,todos: state.todos.map((todo) =>todo.id === action.payload? { ...todo, completed: !todo.completed }: todo),};case "DELETE_TODO":return {...state,todos: state.todos.filter((todo) => todo.id !== action.payload),};default:return state;}
};// 使用 useReducer
const [state, dispatch] = useReducer(todoReducer, {todos: [],filter: "all",
});// 分發 action
dispatch({ type: "ADD_TODO", payload: { id: 1, text: "學習 React" } });
dispatch({ type: "TOGGLE_TODO", payload: 1 });

3. 保存可變數據,更改時不觸發渲染

useRef

用途:?保存可變值,不觸發重新渲染

語法:

const refContainer = useRef(initialValue);

特點:

  • 值的變化不會觸發組件重新渲染
  • 可以訪問 DOM 元素
  • 適合存儲不需要觸發渲染的數據

使用場景:

// 訪問 DOM 元素
const inputRef = useRef(null);
const focusInput = () => {inputRef.current.focus();
};// 存儲定時器 ID
const timerRef = useRef(null);
useEffect(() => {timerRef.current = setInterval(() => {console.log("定時器執行");}, 1000);return () => {if (timerRef.current) {clearInterval(timerRef.current);}};
}, []);// 存儲前一次的值
const prevCountRef = useRef();
useEffect(() => {prevCountRef.current = count;
});// 存儲實例變量
const instanceRef = useRef({isMounted: false,data: null,
});

最佳實踐

性能優化

// 1. 合理使用 useMemo 和 useCallback
const expensiveValue = useMemo(() => {return heavyComputation(data);
}, [data]);const handleClick = useCallback(() => {// 處理點擊事件
}, [dependencies]);// 2. 避免在渲染中創建對象/函數
// ? 錯誤做法
const Component = () => {const [count, setCount] = useState(0);// 每次渲染都會創建新對象const style = { color: "red" };const handleClick = () => setCount(count + 1);return (<div style={style} onClick={handleClick}>{count}</div>);
};// ? 正確做法
const Component = () => {const [count, setCount] = useState(0);const style = useMemo(() => ({ color: "red" }), []);const handleClick = useCallback(() => setCount((prev) => prev + 1), []);return (<div style={style} onClick={handleClick}>{count}</div>);
};

狀態管理選擇

// 簡單狀態 - 使用 useState
const [isVisible, setIsVisible] = useState(false);
const [userName, setUserName] = useState("");// 復雜狀態 - 使用 useReducer
const [formState, dispatch] = useReducer(formReducer, {fields: {},errors: {},isValid: false,
});// 不需要渲染的數據 - 使用 useRef
const previousValue = useRef(null);
const timeoutId = useRef(null);

依賴項管理

// 1. 正確設置依賴項
useEffect(() => {fetchData(userId);
}, [userId]); // 包含所有依賴項// 2. 使用 useCallback 避免依賴項變化
const fetchData = useCallback((id) => {// 獲取數據邏輯
}, []); // 空依賴數組// 3. 使用 useRef 存儲最新值
const latestValue = useRef(value);
useEffect(() => {latestValue.current = value;
});useEffect(() => {const timer = setInterval(() => {console.log(latestValue.current); // 總是獲取最新值}, 1000);return () => clearInterval(timer);
}, []); // 不需要依賴 value

常見陷阱

1. 過度優化

// ? 不必要的 useMemo
const simpleValue = useMemo(() => count + 1, [count]);// ? 直接計算
const simpleValue = count + 1;

2. 依賴項遺漏

// ? 遺漏依賴項
useEffect(() => {console.log(count);
}, []); // 缺少 count 依賴// ? 正確設置依賴項
useEffect(() => {console.log(count);
}, [count]);

3. 閉包陷阱

// ? 閉包陷阱
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {console.log(count); // 總是打印初始值
}, []); // 空依賴數組// ? 解決方案 1: 添加依賴項
const handleClick = useCallback(() => {console.log(count);
}, [count]);// ? 解決方案 2: 使用函數式更新
const handleClick = useCallback(() => {setCount((prevCount) => {console.log(prevCount);return prevCount + 1;});
}, []);

總結

選擇合適的 Hook 取決于具體的使用場景:

  • useMemo/useCallback: 用于性能優化,緩存計算結果和函數
  • useState/useReducer: 用于狀態管理,狀態變化會觸發重新渲染
  • useRef: 用于存儲不需要觸發渲染的可變數據

合理使用這些 Hook 可以提升組件性能,避免不必要的重新渲染,同時保持代碼的可讀性和可維護性。

?React Hooks 完全指南:從基礎到高級的實戰技巧 - 高質量源碼分享平臺-免費下載各類網站源碼與模板及前沿技術分享

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

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

相關文章

PCIe 6.0 vs 5.0:帶寬翻倍背后的技術革命

PCIe 6.0 vs 5.0&#xff1a;帶寬翻倍背后的技術革命在數據中心、AI計算和高速存儲需求爆炸式增長的今天&#xff0c;傳統接口帶寬已成為系統性能提升的瓶頸。PCIe 6.0的推出正是為了解決這一挑戰&#xff0c;它通過革命性的技術創新&#xff0c;在保持向后兼容的同時實現了帶寬…

突破傳統企業組網瓶頸:某科技公司智能組網服務項目深度解析

在現代企業的數字化轉型過程中&#xff0c;穩定、高效、安全的網絡基礎設施已成為業務發展的關鍵。然而&#xff0c;傳統組網方案往往面臨諸多挑戰&#xff0c;如網絡性能不足、組網復雜度高、擴展性不佳、以及安全防護薄弱等問題。為了解決這些痛點&#xff0c;某科技公司通過…

ubuntu單機實現10000個連接同時在線測試

連接前 成功連接后 前端測試連接腳本: c_5k.sh !/bin/bash ulimit -n 100000 # client_simulator.sh SERVER_IP="192.168.0.106" SERVER_PORT=8080 MAX_CLIENTS=5000 BATCH_SIZE=100echo "Starting $MAX_CLIENTS clients to $SERVER_IP:$SERVER_PORT"…

防護墻技術(一):NAT

###源NAT基本原理 NAT&#xff08;Network Address Translation&#xff09;網絡地址轉換技術 源NAT技術對IP報文的源地址進行轉換&#xff0c;將私有IP地址轉換為公網IP地址&#xff0c;使大量私網用戶可以利用少量公網IP地址訪問internet&#xff0c;大大減少對公網IP的消耗 …

動態規劃2(c++)

酒鬼#include <bits/stdc.h> using namespace std; int main() {int n;cin>>n;int a[10010];for(int i 1;i<n;i){cin>>a[i];}int dp[1010][5] {0};dp[0][0] 0;dp[1][0] 0;dp[1][1] a[1];dp[1][2] 0;dp[2][0] a[1];dp[2][1] a[2];dp[2][2] a[1]a[…

「LangChain 學習筆記」LangChain大模型應用開發:代理 (Agent)

「LangChain大模型應用開發」 系列文章目錄&#xff1a; LangChain大模型應用開發&#xff1a;模型&#xff0c;提示和輸出解釋器 LangChain大模型應用開發&#xff1a;儲存(Memory) LangChain大模型應用開發&#xff1a;模型鏈&#xff08;Chains&#xff09; LangChain大模…

python pyqt5開發DoIP上位機【介紹】

目錄文章合集一、核心功能概述二、主要模塊解析1. 導入的庫2. 輔助函數3. DOIP協議處理&#xff08;DOIPProtocol類&#xff09;4. 網絡工具&#xff08;NetworkUtils類&#xff09;5. 通信線程&#xff08;DOIPCommunicationThread類&#xff09;6. UDS命令輸入組件&#xff0…

從零實現一個可擴展的規則解析引擎 —— 支持 AND/OR 優先級、短路求值與多類型運算符

在日常業務開發中&#xff0c;我們經常需要基于一些“規則”來決定程序的走向。比如&#xff1a; 客服機器人 根據用戶問題領域和復雜度選擇不同的模型&#xff1b;營銷系統 根據用戶畫像匹配不同優惠券&#xff1b;風控引擎 根據請求參數、時間、分值判定是否放行。 這些規則往…

Preprocessing Model in MPC 3 - 基于同態加密的協議 - Over Rings 環

參考論文&#xff1a;SoK: Multiparty Computation in the Preprocessing Model MPC (Secure Multi-Party Computation) 博士生入門資料。抄襲必究。 本系列教程將逐字解讀參考論文(以下簡稱MPCiPPM)&#xff0c;在此過程中&#xff0c;將論文中涵蓋的40篇參考文獻進行梳理與講…

uni-app 跨平臺項目的 iOS 上架流程:多工具組合的高效協作方案

跨平臺框架的興起&#xff0c;讓許多團隊選擇 uni-app 來開發移動應用。 一套代碼多端運行&#xff0c;確實大大降低了研發成本&#xff0c;但當項目進入 iOS 上架階段 時&#xff0c;很多團隊依舊面臨挑戰&#xff1a;證書復雜、環境不統一、上傳繁瑣。 本文結合實戰經驗&…

掌握 Linux 文件權限:chown 命令深度解析與實踐

在 Linux 系統的日常運維與開發工作里&#xff0c;文件權限管理是保障系統安全、規范文件訪問的關鍵環節。其中&#xff0c;chown 命令作為修改文件所有者及關聯組的核心工具&#xff0c;對精準把控文件權限起著重要作用。接下來&#xff0c;我們將全面拆解 chown 命令&#xf…

計算機算術7-浮點基礎知識

1. 浮點表示其中b表示基底&#xff0c;e表示指數&#xff0c;s表示尾數&#xff0c;注意在s的表示過程中&#xff0c;有個隱藏1.同時還有個符號位從下面這個圖可以看出&#xff0c;向上溢出和向下溢出的概念&#xff0c;overflow表示的是數的絕對值超過了最大的表示范圍&#x…

設計模式8-命令模式

定義 Command Partern: 將一個請求封裝成一個對象&#xff0c;從而讓你使用不同的請求把客戶端參數化&#xff0c;對請求排隊或者記錄請求日志&#xff0c;可以提供命令的撤銷和恢復功能。&#xff08;核心思想是將“動作”與“執行者”解耦&#xff09; 場景 GUI&#xff1a;…

數據結構(順序表力扣刷題)

1.移除元素 給你一個數組 nums 和一個值 val&#xff0c;你需要 原地 移除所有數值等于 val 的元素。元素的順序可能發生改變。然后返回 nums 中與 val 不同的元素的數量。 假設 nums 中不等于 val 的元素數量為 k&#xff0c;要通過此題&#xff0c;您需要執行以下操作&…

機器學習 - Kaggle項目實踐(6)Dogs vs. Cats Redux: Kernels Edition 貓狗二分類

Dogs vs. Cats Redux: Kernels Edition | Kaggle 任務&#xff1a;給定貓狗圖像數據集 進行二分類。 Cats or Dogs - using CNN with Transfer Learning | Kaggle&#xff08;參考&#xff09; Cats or Dogs | Kaggle &#xff08;我的kaggle&#xff09; 本文介紹了使用Re…

基礎的匯編指令

目錄 1、接上一個csdn特殊功能寄存器 1.1CPSR寄存器 1.2SPSR寄存器 1.3CPSR寄存器的高四位和第四位 ?編輯 2、匯編指令的分類 3、匯編指令的基本格式 4、數據搬移指令&#xff08;賦值指令&#xff09; 4.1指令碼 4.2指令格式 4.3測試代碼 4.5立即數 4.6ldr偽指令 …

Docker實戰避坑指南:從入門到精通

摘要&#xff1a;文人結合自身微服務實踐&#xff0c;系統梳理從安裝適配、鏡像拉取&#xff0c;到運行配置、構建優化、多容器編排、數據持久化、監控運維等 Docker 全流程高頻踩坑點&#xff0c;給出可落地的解決方案&#xff0c;幫助讀者快速規避同類問題并提升容器化效率。…

《Bishop PRML》10.1. Variational Inference(2)理解VAE

通過VAE與AE理解變分分布的變量 如何理解變分推斷公式中,Z和X的含義是什么? 知乎 變分自編碼器VAE的數學原理。 csdn 變分自編碼器(VAE)的數學原理以及實現 Loss functions in Variational Autoencoders (VAEs) 一文解釋 VAE+ELBO AE的編碼和解碼是確定性的。VAE的解碼過程…

函數調用中的初始化與賦值——深入理解C++對象的生命周期

技術博客&#xff1a;函數調用中的初始化與賦值——深入理解C對象的生命周期引言在C編程中&#xff0c;理解函數調用過程中參數傳遞、對象創建和返回值處理的細節對于編寫高效且無誤的代碼至關重要。本文將通過一個具體的例子來探討函數調用時實參到形參的轉換過程&#xff0c;…

矩陣微積分的鏈式法則(chain rule)

矩陣微積分的鏈式法則&#xff08;chain rule&#xff09;與標量情況一樣&#xff0c;用于求復合函數的導數&#xff0c;但由于涉及矩陣和向量的求導&#xff0c;維度匹配和布局約定&#xff08;numerator-layout vs. denominator-layout&#xff09;必須格外小心。下面給出常見…