はじめに
できるだけ文章量を減らして見た目とイメージで。
全体のイメージ
下記使用パターンの1と2はほぼ必須、3と4は状況に応じて。
「必要に応じて」はなぜかというと、こちらの記事にあるように
MOST OF THE TIME YOU SHOULD NOT BOTHER OPTIMIZING UNNECESSARY RERENDERS.
必要のない再レンダリングは特に大きな影響を及さなければ過度に気にする必要がないためです。
1. useEffect内でpropsで渡ってくる関数を呼ぶ際
useCallback
とuseMemo
を使い、useEffect内の関数が何度も呼ばれるのを防ぐ。
const Parent = () => {
// useCallbackを使わないとParentがレンダリングする度に
// aが新しく作られ、ChildのuseEffect内のfooも毎回実行されてしまう
const a = useCallback(() => {}, []); // 何かしらの関数
// 関数にはcallback、配列とオブジェクトにはuseMemoを使う
// (useMemoを使わないとレンダリング毎に参照が変わるため)
const b = useMemo(() => [1, 2, 3], []); // 何かしらの配列
return <Child a={a} b={b} />;
};
const Child = ({ a, b }) => {
useEffect(() => {
const options = { a, b };
foo(options);
}, [a, b]);
return <div>Child</div>;
};
2. カスタムフックが関数や配列、オブジェクトを返す際
利用箇所ごとに必要に応じてuseCallback
やuseMemo
を追加することを避けるため、カスタムフックには組み込んでおく(組み込んでおくことによるオーバーヘッドは大きくないため)
export const useSomeCustomHook = () => {
const a = useCallback(() => {}, []); // 何かしらの関数
const b = useMemo(() => [1, 2, 3], []); // 何かしらの配列
return { a, b }
};
3. React.memoを使ってできるだけ再レンダリングを避けたい際
propsに関数や配列、オブジェクトを渡す場合、useCallback
もしくはuseMemo
を使わないとReact.memo
を使っていても親がレンダリングするたびにコンポーネントが再レンダリングしてしまう(つまりReact.memo
を使う意味がなくなる)。ただしReact.memo
を必要以上に使用すると逆にメモリを消費する可能性があるため、基本はあまり使わない(アニメーションなどで使用)。
const Parent = () => {
const a = useCallback(() => {}, []); // 何かしらの関数
const b = useMemo(() => [1, 2, 3], []);
return <Child a={a} b={b} />;
};
const Child = memo(SomeComponent);
4. 重い処理の関数を実行する際
useMemo
の出番。ただしこちらも必要な時だけ使うようにする。
const SomeComponent = ({ a, b }) => {
const result = useMemo(() => someHeavyProcess(a, b), [a, b]);
return <div>{result}</div>;
};
さいごに
いつもこの辺り頭で整理している気がするのでまとめました。しばらくreactを使わない期間などあったりしてもすぐに理解が取り戻せるよう、できるだけ文章少なめにしています。