はじめに
この記事はReactの不要な再レンダリングを防ぐ,React.memo
、useCallback
についての備忘録です.
React.memo
React.memoは,コンポーネントをメモ化しておくことで不要な再レンダリングを防ぎます.
具体的には,propsが変わらない限り,コンポーネントを再レンダリングしません
.
例:以下のコードでは,Child2
コンポーネントがメモ化されています.
通常,stateが更新されると親が再レンダリングされ,子コンポーネントも再レンダリングされます.
そのため,countやtoggleが変更されたとき,Child1
は再レンダリングされます.
一方で,メモ化されたChild2
はpropsであるcountが変更されない限り再レンダリングはされません.
つまり,渡されているprops以外(ここではtoggle)が変化した時の親コンポーネントの再レンダリングによる,子コンポーネントの不要なレンダリングを防ぐことができます.
import React, { useState, memo } from "react";
const Child1 = ({ count }) => {
console.log("メモされていないChild1が再レンダリングされました");
return <div>カウント: {count}</div>;
};
const Child2 = memo(({ count }) => {
console.log("メモ化されたChild2が再レンダリングされました");
return <div>カウント: {count}</div>;
});
const Parent = () => {
const [count, setCount] = useState(0);
const [toggle, setToggle] = useState(false);
return (
<>
<button onClick={() => setCount(count + 1)}>カウント増加</button>
<button onClick={() => setToggle(!toggle)}>トグル</button>
<Child1 count={count} />
<Child2 count={count} />
</>
);
};
useCallback
useCallbackは関数をメモ化します.React.memoと使うことで不要な再レンダリングを防ぐことができます.
前提として,stateの更新等で再レンダリングされるときには,コンポーネント内の関数も再生成されます.
例:以下のコードでは,countが更新されるとき
countを更新→Parent
が再レンダリング→handleClick
の再生成
となります.そのため,Child
コンポーネントをReact.memoでメモ化していても,渡されているpropsが変化しているので,Child
コンポーネントは再レンダリングされます.
import React, { useState, useCallback, memo } from 'react';
const Child = memo(({ onClick }) => {
console.log('Childが再レンダリングされました');
return (
<div>
<button onClick={onClick}>子のボタン</button>
</div>
);
});
const Parent = () => {
const [count, setCount] = useState(0);
const handleClick = () => {
console.log('子のボタンがクリックされました');
}
return (
<div>
<h2>カウント: {count}</h2>
<button onClick={() => setCount((prev) => prev + 1)}>カウント増加</button>
<Child onClick={handleClick} />
</div>
);
};
ここで,useCallback
を使用し関数をメモ化しておくことで,再レンダリングを防ぐことができます.
以下のコードでは,handleClick
をuseCallback
でメモ化しています.これにより,
countを更新 → Parent
が再レンダリング → handleClick
はメモ化されているので再生成されない.
となります.つまり,Child
コンポーネントのpropsの変化を防いでいるため,結果,Child
コンポーネントは再レンダリングされません.
import React, { useState, useCallback, memo } from 'react';
const Child = memo(({ onClick }) => {
console.log('Childが再レンダリングされました');
return (
<div>
<button onClick={onClick}>子のボタン</button>
</div>
);
});
const Parent = () => {
const [count, setCount] = useState(0);
// useCallback を使うことで、関数の参照が変わらなくなる
const handleClick = useCallback(() => {
console.log('子のボタンがクリックされました');
}, []);
return (
<div>
<h2>カウント: {count}</h2>
<button onClick={() => setCount((prev) => prev + 1)}>カウント増加</button>
<Child onClick={handleClick} />
</div>
);
};
まとめ
- React.memoはコンポーネントをメモ化
- useCallbackは関数をメモ化
おわりに
この記事は以下の記事を参考にさせていただいています.