はじめに
できるだけ文章量を減らして見た目とイメージで。
全体のイメージ
下記使用パターンの1と2はできるだけやった方が良く、3は状況に応じて。
「必要に応じて」はなぜかというと、こちらの記事にあるように
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 ChildComponent = ({ a, b }) => {
useEffect(() => {
const options = { a, b };
foo(options);
}, [a, b]);
return <div>Child</div>;
};
// 実はこれでは足りず、useCallback/useMemoを使っていても
// まだ再レンダリングが走る。React.memoで包む必要がある
const Child = memo(ChildComponent);
2. カスタムフックが関数や配列、オブジェクトを返す際
利用箇所ごとに必要に応じてuseCallback
やuseMemo
を追加することを避けるため、カスタムフックには組み込んでおく(組み込んでおくことによるオーバーヘッドは大きくないため)
export const useSomeCustomHook = () => {
const a = useCallback(() => {}, []); // 何かしらの関数
const b = useMemo(() => [1, 2, 3], []); // 何かしらの配列
return { a, b }
};
3. 重い処理の関数を実行する際
useMemo
の出番。ただしこちらも必要な時だけ使うようにする(場合によってはメモリーを大きく消費することがあるため)
const SomeComponent = ({ a, b }) => {
const result = useMemo(() => someHeavyProcess(a, b), [a, b]);
return <div>{result}</div>;
};
さいごに
いつもこの辺り頭で整理している気がするのでまとめました。しばらくreactを使わない期間などあったりしてもすぐに理解が取り戻せるよう、できるだけ文章少なめにしています。