🧗‍♂️

【React入門】絶対に理解させる(たい)useMemo【初学者向け】

2024/08/20に公開

まえがき

React Hooksの中の一つ、useMemoについて解説する。厳密で難しい話をするのではなく、理解させることを目的としている。

対象読者

  • React勉強中の方
  • useStateはギリいけるぞって方

useMemoって何

  • 重たい処理・計算結果の値を保持して、無駄な計算をしないようにするためのHooks
  • パフォーマンスを向上させる目的のHooksであるから、useMemoがないと実装できないってことは基本的にない

処理のサンプルコード

まず重い処理をするコードを見てくれ

  const culc = (x: number, y: number) => {
    let i = 0;
    while (i < 10000) {
      console.log("重い処理だよ");
      i++;
    }
    return x * y;
  };

この関数は重たい処理をして、結果的に引数の二つの数値の積を返すぞ

useMemoを利用しない場合

次に、メモ化せずにこの関数の返り値を使うコードを見てくれ

const [x, setX] = useState<number>(10);
const [y, setY] = useState<number>(20);

const result = culc(x, y);

ごく普通の実装だ。この状態で、同じ画面にあるx,yの増減に全く関係ないボタン(Stateを変更する)を押してみる


(自ブログの開発画面です)

x,yの値が全く変わっていないにもかかわらず、ボタンを押すたびに毎回関数が実行されてconsoleが表示されている。これは明らかに不要な実行である。

このように、useMemoを利用していないresultは、コンポーネントが再レンダリングされるたびに計算される。

再レンダリングって何

  • 画面を更新(再描画)するために、JavaScriptをもう一回読み込み直すことだぞ
  • 基本的に以下のタイミングで再レンダリングが走るぞ
    • 自コンポーネントのPropsが更新された時
    • 自コンポーネントのStateが変更された時 ← 今回はボタンを押してStateが変更されたからこれ
    • 親コンポーネントが再レンダリングされた時

useMemoを利用した場合

では、useMemoを利用して関数の返り値をメモ化(保持)するコードを見てくれ

  const [x, setX] = useState<number>(10);
  const [y, setY] = useState<number>(20);

  const memoResult = useMemo(() => culc(x, y), [x, y]);

この状態で、同じ画面にあるx,yの増減に全く関係ないボタン(Stateを変更する)を押してみる
すると、全くconsoleが表示されない。つまり、関数が実行されていないということになる。
本来、x * yを計算するというこの関数は、x,yのどちらも変更がない場合は、再レンダリングの際にいちいち再計算する必要がないので、これで不要な処理をスキップし、パフォーマンスを向上させることができた。
もちろんx,yが変更される場合(x,yを変化させるボタンの押下時など)はmemoResultの値は再計算される。

一般化した使い方の例

  const memoResult = useMemo(() => {
    // ここに処理を書く
  }, [依存する変数をここに並べる(依存配列という)]);
  • 依存する変数が変わらない限り、処理は実行されないぞ
  • 処理が重たい時に効果を発揮するぞ(再計算が不必要な時にスキップされるため)
  • 処理に使う変数を依存配列に入れるぞ(過不足なく入れることが重要)

依存配列に何を入れるべきか

const memoResult = useMemo(() => {
    let i = 0;
    while (i < 10000) {
      console.log("メモされてる方");
      i++;
    }
    return x * y;
  }, [x, y]);

もしこのコードの依存配列が[x]のみだったら、もしyのみが変更された時、useMemoの処理が実行されないのでx * yが更新されない。これは間違った実装である。

逆に、依存配列が[x, y, z]であったら、zのみが変更された場合にもuseMemoの処理が実行される。しかし、計算結果はx * yであるから、計算結果の変化は全くない。つまり依存配列にzは必要なく、間違った実装である。

よって、関数に必要である変数を過不足なく依存配列に入れる必要がある。

まとめ

  • useMemoはReactのHooksで、計算結果をメモ化することでパフォーマンスを向上させる
  • useMemoを使わない場合、コンポーネントが再レンダリングされるたびに計算が実行される
  • useMemoを使用すると、指定した依存配列が変わらない限り、以前の計算結果を再利用する
  • useMemoは、重い計算処理が頻繁に行われる場合や、同じ結果が再利用できる場合に使用すると効果的

このようにして、useMemoを使うことでReactコンポーネントのパフォーマンスを向上させることができるぞ🚗

Discussion