React??memo允許你的組件在?props?沒有改變的情況下跳過重新渲染的問題記錄
memo(Component, arePropsEqual?)
使用 memo 將組件包裝起來,以獲得該組件的一個 記憶化 版本。通常情況下,只要該組件的 props 沒有改變,這個記憶化版本就不會在其父組件重新渲染時重新渲染。但 React 仍可能會重新渲染它:記憶化是一種性能優(yōu)化,而非保證。
import { memo } from 'react'; const SomeComponent = memo(function SomeComponent(props) { // ... });
參數(shù)
- Component:要進(jìn)行記憶化的組件。memo 不會修改該組件,而是返回一個新的、記憶化的組件。它接受任何有效的 React 組件,包括函數(shù)組件和 forwardRef 組件。
- 可選參數(shù) arePropsEqual:一個函數(shù),接受兩個參數(shù):組件的前一個 props 和新的 props。如果舊的和新的 props 相等,即組件使用新的 props 渲染的輸出和表現(xiàn)與舊的 props 完全相同,則它應(yīng)該返回 true。否則返回 false。通常情況下,你不需要指定此函數(shù)。默認(rèn)情況下,React 將使用 Object.is 比較每個 prop。
返回值
memo 返回一個新的 React 組件。它的行為與提供給 memo 的組件相同,只是當(dāng)它的父組件重新渲染時 React 不會總是重新渲染它,除非它的 props 發(fā)生了變化。
用法
當(dāng) props 沒有改變時跳過重新渲染
React 通常在其父組件重新渲染時重新渲染一個組件。你可以使用 memo 創(chuàng)建一個組件,當(dāng)它的父組件重新渲染時,只要它的新 props 與舊 props 相同時,React 就不會重新渲染它。這樣的組件被稱為 記憶化的(memoized)組件。
要記憶化一個組件,請將它包裝在 memo 中,使用它返回的值替換原來的組件:
const Greeting = memo(function Greeting({ name }) { return <h1>Hello, {name}!</h1>; }); export default Greeting;
React 組件應(yīng)該始終具有 純粹的渲染邏輯。這意味著如果其 props、state 和 context 沒有改變,則必須返回相同的輸出。通過使用 memo,你告訴 React 你的組件符合此要求,因此只要其 props 沒有改變,React 就不需要重新渲染。即使使用 memo,如果它自己的 state 或正在使用的 context 發(fā)生更改,組件也會重新渲染。
在此示例中,請注意 Greeting 組件在 name 更改時重新渲染(因為那是它的 props 之一),但是在 address 更改時不會重新渲染(因為它不作為 props 傳遞給 Greeting):
import { memo, useState } from 'react'; export default function MyApp() { const [name, setName] = useState(''); const [address, setAddress] = useState(''); return ( <> <label> Name{': '} <input value={name} onChange={e => setName(e.target.value)} /> </label> <label> Address{': '} <input value={address} onChange={e => setAddress(e.target.value)} /> </label> <Greeting name={name} /> </> ); } const Greeting = memo(function Greeting({ name }) { console.log("Greeting was rendered at", new Date().toLocaleTimeString()); return <h3>Hello{name && ', '}{name}!</h3>; });
更改Address,Geeting沒有重渲染。
更改name,Greeting重新渲染了
在每個地方都應(yīng)該添加 memo 嗎?
如果你的應(yīng)用像此站點一樣,大多數(shù)交互是粗略的(例如直接替換頁面或整個部分),那么通常不需要記憶化。另一方面,如果你的應(yīng)用更像是繪圖編輯器,大多數(shù)交互是細(xì)粒度的(例如移動圖形),那么你可能會發(fā)現(xiàn)記憶化非常有用。
只有當(dāng)你的組件經(jīng)常使用完全相同的 props 重新渲染時,并且其重新渲染邏輯是非常昂貴的,使用 memo 優(yōu)化才有價值。如果你的組件重新渲染時沒有明顯的延遲,那么 memo 就不必要了。請記住,如果傳遞給組件的 props 始終不同,例如在渲染期間傳遞對象或普通函數(shù),則 memo 是完全無用的。這就是為什么你通常需要在 memo 中同時使用 useMemo
和 useCallback
。
在其他情況下將組件包裝在 memo 中是沒有任何好處的。這種做法也沒有什么明顯的危害,因此一些團(tuán)隊會選擇不考慮個別情況,并盡可能使用 memo。這種方法的缺點是代碼變得不易讀。此外,并不是所有的記憶化都是有效的:一個“總是新的”值足以破壞整個組件的記憶化。
實踐中,你可以通過遵循一些原則來使許多 memoization 變得不必要:
當(dāng)一個組件在視覺上包裹其他組件時,讓它 接受 JSX 作為子組件。這樣,當(dāng)包裝組件更新其自身狀態(tài)時,React 知道其子組件不需要重新渲染。
優(yōu)先使用局部狀態(tài),并且不要將 狀態(tài)提升 到不必要的層級。例如,不要將短暫狀態(tài)(如表單數(shù)據(jù)和項元素是否 hover 狀態(tài))保留在樹的頂部或全局狀態(tài)庫中。
保持你的 渲染邏輯純粹。如果重新渲染組件會導(dǎo)致問題或產(chǎn)生一些明顯的視覺瑕疵,則這是你組件中的 bug!修復(fù) bug 而不是添加 memoization。
避免 不必要的 Effect 來更新狀態(tài)。React 應(yīng)用中的大多數(shù)性能問題都是由于 Effect 引起的更新鏈,這些 Effect 會使你的組件一次又一次地重新渲染。
嘗試 從你的 Effect 中刪除不必要的依賴項。例如,與其使用 memoization,不如將某些對象或函數(shù)移動到 Effect 內(nèi)部或組件外部,這通常更簡單。
如果特定交互仍然感覺不流暢,請 使用 React 開發(fā)者工具 profiler 來查看哪些組件最需要 memoization,并在需要時添加 memoization。這些原則使你的組件更易于調(diào)試和理解,因此建議在任何情況下都遵循它們。從長遠(yuǎn)來看,我們正在研究 自動進(jìn)行細(xì)粒度 memoization,以解決這個問題。
當(dāng)組件的某個 prop 是對象、數(shù)組或函數(shù)時,我的組件會重新渲染。
React 通過淺比較來比較舊的和新的 prop:也就是說,它會考慮每個新的 prop 是否與舊 prop 引用相等。如果每次父組件重新渲染時創(chuàng)建一個新的對象或數(shù)組,即使它們每個元素都相同,React 仍會認(rèn)為它已更改。同樣地,如果在渲染父組件時創(chuàng)建一個新的函數(shù),即使該函數(shù)具有相同的定義,React 也會認(rèn)為它已更改。為了避免這種情況,可以簡化 props 或在父組件中記憶化(memoize)props。
官網(wǎng)講解: memo
到此這篇關(guān)于React memo允許你的組件在 props 沒有改變的情況下跳過重新渲染的文章就介紹到這了,更多相關(guān)React 重新渲染內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用React-router+Webpack快速構(gòu)建react程序
目前 React、Webpack 等技術(shù)如火如荼,你是不是還在愁苦如何把這些雜亂的知識怎么學(xué)習(xí)一下,開啟一段新的前端開發(fā)之路呢?那么這篇將給大家運用示例代碼詳細(xì)的介紹使用React-router和Webpack如何快速構(gòu)建一個react程序,感興趣的朋友們下面來一起看看吧。2016-10-10使用webpack配置react-hot-loader熱加載局部更新
這篇文章主要介紹了使用webpack配置react-hot-loader熱加載局部更新,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01