React性能優化終極指南:memo、useCallback、useMemo全解析

掌握 React.memo、useCallback、useMemo 的正確使用姿勢,讓你的 React 應用性能飛起來!


🎯 React.memo 作用

React.memo?是一個高階組件,用于函數組件,通過淺比較 props 的變化來決定是否重新渲染。如果 props 沒有變化,組件就會跳過渲染,復用之前的渲染結果,從而提升性能。

🤔 React.memo 可以避免組件重復渲染,是不是所有組件都應該它包裹?

📋 React.memo 使用原則

? 什么情況下使用:

🎨?場景 1:組件渲染成本高

如果組件內部有復雜計算、大量子節點或高頻交互(如動畫、圖表),且父組件頻繁觸發無關渲染時,使用 React.memo 可減少重復渲染。

??場景 2:Props 變化頻率低

當組件的 props 大多數情況下穩定,只有少數情況會變化時(如配置型組件),React.memo 能有效避免因父組件狀態變化導致的無效渲染。

🔗?場景 3:傳遞了非穩定 Props

如果父組件傳遞的 props 是內聯對象或函數(如?onClick={() => {...}}),且未通過 useMemo/useCallback 緩存,子組件用 React.memo 可能無效,需結合緩存使用。

? 什么情況下不使用:

🪶?場景 1:組件本身渲染成本極低

如果組件只是簡單渲染文本或少量 DOM 節點(如?<Button>),React.memo 的 props 淺比較成本可能高于直接渲染的成本,得不償失。

🔄?場景 2:Props 頻繁變化

如果組件的 props 每次渲染幾乎都會變化(如實時更新的數據流),使用 React.memo 反而會增加額外的淺比較開銷,優化效果微乎其微。

🍃?場景 3:組件已經是”葉子組件”

如果組件沒有子組件,且不受父組件狀態影響,通常不需要額外優化。

💡 其他優化方式

如果不想濫用 React.memo,可通過其他方式減少渲染:

1.?🎯?狀態隔離:將狀態下沉到更小的組件中,避免全局狀態觸發大范圍渲染。

2.?🧩?組件拆分:將高頻變動的部分和低頻變動的部分拆分為獨立組件。

3.?🔑?使用 key 屬性:強制重置組件實例,避免內部狀態混亂(如列表項)。

4.?📜?虛擬化長列表:對長列表使用 react-window 或 react-virtualized,減少 DOM 節點數量。


🔄 useCallback 作用

useCallback?是 React 中用于性能優化的鉤子,其主要作用是?緩存函數實例,避免子組件因父組件重新渲染導致的非必要更新。

🤔 useCallback 可以緩存方法,是不是所有方法都應該用它優化呢?

📋 useCallback 使用原則

? 什么情況下使用:

🎯?場景 1:子組件使用了 React.memo

如果子組件通過 React.memo 避免重復渲染,且父組件傳遞的方法是一個?非穩定的函數引用(如內聯函數),則需要用 useCallback 包裹,否則子組件會因父組件渲染導致函數引用變化而重新渲染。

// 父組件
const Parent = () => {const [count, setCount] = useState(0);// ? 未使用 useCallback:每次渲染生成新函數,導致子組件重新渲染const handleClickBad = () => console.log("Click");// ? 使用 useCallback:函數引用穩定,子組件不重復渲染const handleClickGood = useCallback(() => {console.log("Click");}, []);return <Child onClick={handleClickGood} />;
};// 子組件
const Child = React.memo(({ onClick }) => {return <button onClick={onClick}>Submit</button>;
});

???場景 2:子組件依賴淺比較優化

如果子組件是 PureComponent 或通過 shouldComponentUpdate 實現了淺比較邏輯,父組件傳遞的函數必須保持引用穩定,否則優化會失效。

class Child extends React.PureComponent {render() {return <button onClick={this.props.onClick}>Submit</button>;}
}
? 什么情況下不使用:

🚫?場景 1:子組件無渲染優化

如果子組件沒有使用 React.memo、PureComponent 或自定義的渲染優化邏輯,即使父組件傳遞的函數引用變化,也不會帶來明顯的性能問題。

// 子組件未優化,函數引用變化不影響性能
const Child = ({ onClick }) => <button onClick={onClick}>Submit</button>;

🔄?場景 2:函數依賴頻繁變化的值

如果函數內部依賴頻繁變化的 state 或 props,且需要?實時獲取最新值,此時 useCallback 需明確聲明依賴項,可能導致函數頻繁重建,反而失去優化意義。

const Parent = () => {const [text, setText] = useState("");// ? 依賴 text 變化,useCallback 無法避免重建const handleSubmit = useCallback(() => {console.log(text); // 需要最新的 text}, [text]);return <Child onSubmit={handleSubmit} />;
};

💡?場景 3:替代方案:直接傳遞內聯函數

如果子組件渲染成本極低(如簡單按鈕),且父組件渲染頻率不高,可以直接傳遞內聯函數,避免過度優化。

const Parent = () => {return <Child onClick={() => console.log("Click")} />;
};

📊 性能權衡建議

🎯 場景是否需要 useCallback💡 原因
子組件通過 React.memo/PureComponent 優化? 需要避免函數引用變化導致子組件無效渲染
子組件無優化且渲染成本低? 不需要優化收益小于比較成本
函數依賴高頻變化的值? 謹慎使用可能導致頻繁重建函數
函數作為副作用依賴(如 useEffect)? 需要避免副作用重復觸發

📝 總結

??優先使用 useCallback:當子組件有明確的渲染優化策略時(如 React.memo)。

???無需強制使用:如果子組件渲染成本低或函數依賴頻繁變化的值。

🚫?避免濫用:過度使用 useCallback 可能導致代碼復雜度上升,需結合性能分析工具(如 React DevTools)驗證優化效果。


💾 useMemo 作用

useMemo?是 React 中的一個性能優化 Hook,核心作用是通過緩存復雜計算結果,避免組件重復渲染時不必要的重復計算

? 什么情況下使用:

🔥?場景 1:高開銷計算

當組件內有?計算成本高昂?的操作(如大數據處理、復雜數學運算),且計算結果在多次渲染間可復用時。

const ExpensiveComponent = ({ items }) => {// ? 緩存復雜計算結果const expensiveValue = useMemo(() => {return items.reduce((sum, item) => {return sum + complexCalculation(item);}, 0);}, [items]);return <div>{expensiveValue}</div>;
};

🔗?場景 2:引用穩定性

當需要保持對象或數組的?引用穩定,避免子組件因淺比較重新渲染時。

const Parent = ({ data }) => {// ? 保持對象引用穩定const memoizedData = useMemo(() => ({processedData: data.map((item) => ({ ...item, processed: true })),metadata: { count: data.length, timestamp: Date.now() },}),

[data]

); return <Child data={memoizedData} />; };

🔄?場景 3:依賴其他 Hook 的中間值

當某個值被多個 Hook 依賴,且需要避免重復計算時。

const Component = ({ users, filters }) => {// ? 緩存過濾結果,供多個 Hook 使用const filteredUsers = useMemo(() => {return users.filter((user) => filters.every((filter) => filter(user)));}, [users, filters]);const userCount = useMemo(() => filteredUsers.length, [filteredUsers]);const averageAge = useMemo(() =>filteredUsers.reduce((sum, user) => sum + user.age, 0) /filteredUsers.length,[filteredUsers]);return <UserStats count={userCount} averageAge={averageAge} />;
};

? 什么情況下不使用:

🪶?場景 1:簡單計算

如果計算成本極低(如基本運算、簡單對象合并),直接計算即可。

// ? 不必要的優化
const simpleValue = useMemo(() => a + b, [a, b]);// ? 直接計算即可
const simpleValue = a + b;

??場景 2:頻繁變化的依賴項

如果依賴項頻繁變化(如實時輸入框的值),緩存效果微乎其微,反而增加開銷。

const SearchComponent = ({ query }) => {// ? query 頻繁變化,緩存意義不大const searchResults = useMemo(() => {return performSearch(query);}, [query]);return <SearchResults results={searchResults} />;
};

🍃?場景 3:組件層級低或渲染壓力小

對于葉子組件或渲染壓力較小的組件,優化收益低于 useMemo 自身成本。

📊 useMemo 最佳實踐

??推薦做法:

  1. 🎯?針對性優化:只對真正昂貴的計算使用 useMemo
  2. 📏?合理的依賴項:確保依賴項數組準確且穩定
  3. 🔍?性能測試:使用 React DevTools 驗證優化效果
  4. 🧪?基準測試:對比優化前后的性能差異

??避免的做法:

  1. 🚫?過度優化:不要為每個簡單計算都使用 useMemo
  2. ???錯誤依賴:避免遺漏或添加不必要的依賴項
  3. 🔄?頻繁重建:避免在依賴項頻繁變化時使用

🎉 總結

React 性能優化的三大法寶:React.memouseCallbackuseMemo,各有其適用場景:

🎯?React.memo:適用于渲染成本高、props 變化少的組件
🔄?useCallback:適用于傳遞給優化子組件的函數
💾?useMemo:適用于昂貴計算和引用穩定性需求

記住:性能優化不是銀彈,過度優化反而可能降低性能。始終以實際測試為準,在合適的場景使用合適的優化手段!


💡?小貼士:使用 React DevTools Profiler 來識別性能瓶頸,讓優化更有針對性!

?React性能優化終極指南:memo、useCallback、useMemo全解析 - 高質量源碼分享平臺-免費下載各類網站源碼與模板及前沿技術分享

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

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

相關文章

借助 VR 消防技術開展應急演練,檢驗完善應急預案?

應急演練是企業應對火災事故的重要手段&#xff0c;而 VR 消防技術的應用&#xff0c;為應急演練帶來了全新的體驗和更高的效率。VR 消防技術通過虛擬現實技術模擬逼真的火災場景&#xff0c;讓參與者能夠身臨其境地感受火災發生時的緊張氛圍。某知名物流企業&#xff0c;倉庫眾…

【電賽學習筆記】MaxiCAM 項目實踐——二維云臺追蹤指定目標

前言 本文是對視覺模塊MaixCam實現二維云臺人臉跟蹤_嗶哩嗶哩_bilibili大佬的項目實踐整理與拓展&#xff0c;侵權即刪。 單路舵機基本控制 #導入必要模塊 from maix import pwm, time , pinmap#定義全局變量&#xff0c;設初值 SERVO_FREQ 50 #主頻 SERVO_MIN_DUT…

深入解析 ArkUI 觸摸事件機制:從點擊到滑動的開發全流程

摘要 隨著 HarmonyOS NEXT 的不斷發展&#xff0c;ArkUI 逐漸成為主流的 UI 構建方式。而用戶交互在任何應用中都是基礎而又關鍵的一環&#xff0c;如何利用 ArkUI 提供的觸摸事件機制&#xff0c;如 onTouch、onClick、onSwipe 等&#xff0c;來實現自然、順滑、用戶友好的交互…

Tailwind CSS 自定義工具類與主題配置指南

一、自定義工具類配置在 src/tailwind.css 文件中&#xff0c;我們可以通過 layer utilities 指令添加自定義工具類&#xff1a;tailwind base; tailwind components; tailwind utilities;layer utilities {/* 自定義工具 上下浮動效果 */.animate-floatY {animation: floatY 3…

【代碼隨想錄二刷|704.二分查找、27.移除元素、977.有序數組的平方】

704.二分查找 題目鏈接&#xff1a;704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int search(vector<int>& nums, int target) {//不用二分查找&#xff0c;直接求// for(int i0;i<nums.size();i){// if(nums[i]target)…

基于Vue的工業設備大屏可視化模板(含設備地圖分布+宣傳模塊+報表展示+三維模型加載預覽)

場景 為實現工業設備可視化大屏需求&#xff0c;可實現基于地圖的設備數據管理&#xff0c;點擊具體設備可進行詳細介紹和三維模型展示。 可播放宣傳視頻&#xff0c;可展示PM數據報表等數據&#xff0c;可接受報警數據提醒、統計等數據。 基于現有開源平臺框架進行二次改造…

堆(Heap)優先級隊列(Priority Queue)

一、堆的概念堆&#xff08;Heap&#xff09;是一種特殊的基于樹的數據結構&#xff0c;通常分為最大堆和最小堆兩種類型。它滿足堆屬性&#xff1a;對于最大堆&#xff0c;父節點的值總是大于或等于其子節點的值&#xff1b;而對于最小堆&#xff0c;父節點的值總是小于或等于…

踩坑記錄:因版本不匹配導致 Boost 1.85 編譯失敗的完整解決過程

踩坑記錄&#xff1a;因版本不匹配導致 Boost 1.85 編譯失敗的完整解決過程 轉載請注明出處&#xff0c;歡迎評論區交流。 背景 最近在 Windows 11 VS2022 環境下嘗試用 b2 編譯 Boost 1.85.0&#xff0c;結果一路踩坑&#xff0c;最后發現罪魁禍首是 Boost.Build 自帶的 msv…

InfluxDB Line Protocol 協議深度剖析(二)

四、Line Protocol 寫入操作與實踐&#xff08;一&#xff09;HTTP API 寫入使用 HTTP API 是通過 Line Protocol 寫入數據到 InfluxDB 的常用方式。InfluxDB 1.x&#xff1a;請求方式為 POST&#xff0c;URL 格式為 “http://host:port/write?dbdatabase_name”。其中&#x…

負載均衡:提升業務性能的關鍵技術

一.負載均衡&#xff08;3.6 &#xff09;1.1.什么是負載均衡&#xff1a;負載均衡&#xff1a;Load Balance&#xff0c;簡稱LB&#xff0c;是一種服務或基于硬件設備等實現的高可用反向代理技術&#xff0c;負載均 衡將特定的業務(web服務、網絡流量等)分擔給指定的一個或多個…

【STM32項目】智能家居(版本1)

????大家好&#xff0c;這里是5132單片機畢設設計項目分享&#xff0c;今天給大家分享的是基于《基于STM32的智能家居設計》。 目錄 1、系統功能 2.1、硬件清單 2.2、功能介紹 2.3、控制模式 2、演示視頻和實物 3、系統設計框圖 4、軟件設計流程圖 5、原理圖 6、主…

OpenSCA開源社區每日安全漏洞及投毒情報資訊—2025年7月24日

2025年7月24日安全風險情報資訊在野漏洞風險&#xff08;CVE未收錄&#xff09;&#xff1a;1公開漏洞精選&#xff1a;2組件投毒情報&#xff1a;2在野漏洞風險&#xff08;CVE未收錄&#xff09;1.1 gemini-cli項目潛在命令注入漏洞項目詳情項目描述&#xff1a;gemini-cli是…

飛算 JavaAI 深度實戰:從老項目重構到全棧開發的降本增效密碼

飛算 JavaAI 深度實戰&#xff1a;從老項目重構到全棧開發的降本增效密碼引言正文一、智能引導模塊&#xff1a;老項目重構的 “手術刀” 級解決方案1.1 本地化智能分析&#xff1a;IDEA 插件實操演示1.1.1 &#x1f4cc; IDEA 插件安裝步驟1.1.1.1 首先打開idea工具&#xff0…

分布式推客系統開發全解:微服務拆分、傭金結算與風控設計

一、推客系統概述與市場背景推客系統&#xff08;也稱為分銷系統或社交電商系統&#xff09;已成為現代電商平臺和內容平臺的重要增長引擎。根據最新統計數據&#xff0c;2023年社交電商市場規模已突破3萬億元&#xff0c;占整體電商市場份額的25%以上。推客系統的核心價值在于…

Linux tcpdump 抓取udp 報文

一、tcpdump 支持命令選項tcpdump -i # 指定監聽網絡接口tcpdump -w # 將捕獲到的信息保存到文件中&#xff0c;且不分析和打印在屏幕tcpdump -r # 從文件中讀取數據tcpdump -n # 不把 ip 轉化成域名tcpdump -t # 在每行的輸出中不顯示時間tcpdump -v # 產生詳細的輸出tc…

Oracle數據塊8KB、OS默認認塊管理4KB,是否需調整大小為一致?

上班路上&#xff0c;腦中忽然閃現一個問題&#xff1a;Oracle數據庫塊大小&#xff08;8KB&#xff09;、操作系統文件系統塊大小&#xff08;4KB&#xff09;&#xff0c;為了減少IOPS&#xff0c;需不需要調整為一致&#xff1f;在數據塊保持一致的情況下&#xff0c;針對頻…

卡爾曼濾波器噪聲方差設置對性能影響的仿真研究

卡爾曼濾波器噪聲方差設置對性能影響的仿真研究 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家,覺得好請收藏。點擊跳轉到網站。 1. 引言 卡爾曼濾波器是一種廣泛應用于信號處理、控制系統、導航系統等領域的遞歸估計算法。它通過對系…

“多線程修路:當count++變成災難現場”

1.現象 當我們操作一個線程池的時候&#xff0c;可能需要去計數&#xff0c;也就是統計count&#xff0c;那我們這里有一個疑問&#xff0c;會不會產生線程安全問題&#xff1f; 毫無疑問絕對會有線程安全問題。在線程池環境中&#xff0c;多個線程并發訪問和修改一個共享的 co…

GaussDB null的用法

1 null的定義null 空值代表丟失的未知數據。 默認情況下&#xff0c;表列可以保存 null 值。 本章解釋 is null 和 is not null 操作符。2 null值的贅述如果表中的列是可選的&#xff0c;那么我們可以插入一個新記錄或更新一個現有記錄&#xff0c;而無 需向列添加一個值。這意…

智慧農業新圖景:物聯網如何精準守護作物生長?

在傳統農業生產模式下&#xff0c;農民往往憑借經驗判斷作物生長需求&#xff0c;灌溉、施肥缺乏精準性&#xff0c;導致水資源浪費、土壤板結、作物產量與品質難以提升等問題。加之氣候變化無常&#xff0c;極端天氣頻發&#xff0c;給農業生產帶來諸多不確定性&#xff0c;傳…