目錄
memorized hook是甚麼
memorized hook接受2個參數,第一個是函式,第二個式依賴陣列(dependency array)
它會記住依賴陣列的狀態
,當依賴陣列內的值更新時才會呼叫
callback
因此常用於避免不必要的渲染、計算
useCallback
useCallback是個custom hook,它只能在functional component內使用
常用於記憶function
,以避免組件內的function
在組件被重新渲染時,function又被重新宣告
(重新分配記憶體)
// 這兩個變數用於儲存舊的function
let m;
let n;
const App = () => {
const [count, setCount] = useState(0)
const memoFunction = useCallback(() => {
console.log('memo');
}, []);
const normalFunction = () => {
console.log('normal');
};
// 對比新舊function,確認是否來自同個記憶體位置
console.log(`memoFunction is not change: ${memoFunction === m}`);
console.log(`normalFunction is not change: ${normalFunction === n}`);
return (
<div className="App">
<h1>count: {count}</h1>
<button
type="button"
onClick={() => {
let res = count + 1;
setCount(res);
}}
>
add
</button>
<button
className="ml-3"
type="button"
onClick={() => {
m = memoFunction
n = normalFunction
}}
>
set
</button>
</div>
)
}
useMemo
useMemo是個custom hook,它只能在functional component內使用
常用於記憶function的回傳值
(ex: 經過計算的值),以避免組件內的function在組件被重新渲染時,function被重新呼叫,故能避免不必要的重新計算衝擊效能
const App = () => {
const [count, setCount] = useState(0);
const [number, setNumber] = useState(100);
const res = useMemo(() => {
console.log('calculating');
return count * 10;
}, [count]);
return (
<div className="App">
<h1>
count: {count} / number: {number}
</h1>
<h2>count * 10 = {res}</h2>
<button
type="button"
onClick={() => {
setCount(count + 1);
}}
>
add count
</button>
<button
type="button"
onClick={() => {
setNumber(number + 1);
}}
>
add number
</button>
</div>
)
}
memo
(2023/2/10更新)
常用於記憶組件
,被memo包住的組件
在其父組件更新,但其props沒更新時不會重新渲染
和useCallback一起用能避免父組件
state更新重新渲染時,props沒更新
,但子組件卻重新渲染
const NormalChild = ({content}) => {
console.log('NormalChild re-render');
return (
<div className="border-solid border-2 border-blue-400 p-2">
<h1>{content}</h1>
</div>
)
}
const MemoizedChild = React.memo(({content}) => {
console.log('MemoizedChild re-render');
return (
<div className="border-solid border-2 border-yellow-400 p-2">
<h1>{content}</h1>
</div>
)
});
const App = () => {
const [count, setCount] = useState(0);
const [memoContent, setMemoContent] = useState('memo');
const [normalContent, setNormalContent] = useState('normal');
return(
<div>
<h1>count: {count}</h1>
<button
type="button"
onClick={() => {
setCount(count + 1);
}}
>
add count
</button>
<button
type="button"
onClick={() => {
setCount(count + 1);
setNormalContent('mmm');
setNormalContent('nnn');
}}
>
add count and set content
</button>
<div className='grid grid-cols-2 gap-2'>
{/* num變,但是props沒變 */}
{/* 使用memo,不會重新render */}
<MemoizedChild content={memoContent} />
{/* 會重新render */}
<NormalChild content={normalContent} />
</div>
</div>
);
}
比較表
useCallback | useMemo | memo | |
---|---|---|---|
記憶 | function | function的回傳值 | functional component |
用在functional component內 | 必須 | 必須 | 不建議 |
compare | 依賴陣列 | 依賴陣列 | props的shallow compare |
參考資料
React - useCallback
React - useMemo
React - memo
React 性能優化那件大事,使用 memo、useCallback、useMemo