技術っぽいことを書いてみるブログ

PythonとかVue.jsとか技術的なことについて書いていきます。

Reactについて学ぶ~再計算を防ぐuseMemo編~

はじめに

今回は、ReactのuseMemoについて、学びます。

useMemoの使いどころですか、以下の通りとなります。

  • コンポーネント内における任意の関数を呼び出した結果を後で再利用するために保持しておき、その関数が呼び出されるたびに再計算されることを防ぐ
  • 結果が同じなのにそれが毎回のレンダリングで関数が実行されるのを防ぐ

なお、useMemouseCallback は、不要な再レンダリングを防ぐために提供されている模様

では、早速見ていきましょう

useMemoの使わない場合

  • サンプルコード
import { FC, useMemo, useState } from 'react';

const AboutUseMemo: FC = () => {
  const [countA, setCountA] = useState(0);
  const [countB, setCountB] = useState(999);

  const countUpA = () => {
    console.log('count-up-a');
    setCountA((a) => a + 1);
  };
  const countUpB = () => {
    console.log('count-up-b');
    setCountB((b) => b + 1);
  };

  const heavyFunction = (value: number) => {
    let sum = 0;
    for (let i = 1; i <= 10000000; i++) {
      sum += i;
    }
    console.log(sum);
    return value + 1;
  };

  const hoge = heavyFunction(countA);

  return (
    <div>
      <div>
        <p>{countA}</p>
        <button onClick={countUpA}>Aをカウントアップ</button>
      </div>
      <div>
        <p>{countB}</p>
        <button onClick={countUpB}>Bをカウントアップ</button>
      </div>
      <div>{hoge}</div>
    </div>
  );
};

export default AboutUseMemo;

解説

  • 「Aをカウントアップ」ボタンを押下すると、countAに+1します。
  • 「Bをカウントアップ」ボタンを押下すると、countBに+1します。
  • 画面上の{hoge}の値は、countAに+1した値が表示されます。
    • 計算のため、重い関数が実行されます。(便宜上、重い感じの処理にしていますが、本来なら不要な処理ですね♪)
  • ボタンを押下したときの挙動は…?
    • 「Aをカウントアップ」ボタンを押下すると、heavyFunctionが実行されます。
      • ここはcountAに依存する処理なので、動いても問題ないです。
    • 「Bをカウントアップ」ボタンを押下すると、それでもheavyFunctionが実行されます。
      • 本来ここは動かなくてよいです。なぜなら、この計算結果は変わらないためです。
      • ここで、計算結果をメモしておく仕組み必要になり、登場するのが useMemoとなります。

useMemoの使ってみる

  • サンプルコード
import { FC, useMemo, useState } from 'react';

const AboutUseMemo: FC = () => {
  const [countA, setCountA] = useState(0);
  const [countB, setCountB] = useState(999);

  const countUpA = () => {
    console.log('count-up-a');
    setCountA((a) => a + 1);
  };
  const countUpB = () => {
    console.log('count-up-b');
    setCountB((b) => b + 1);
  };

  const heavyFunction = (value: number) => {
    let sum = 0;
    for (let i = 1; i <= 10000000; i++) {
      sum += i;
    }
    console.log(sum);
    return value + 1;
  };

  // 変更したよ🎵
  const hoge = useMemo(() => heavyFunction(countA), [countA]);

  return (
    <div>
      <div>
        <p>{countA}</p>
        <button onClick={countUpA}>Aをカウントアップ</button>
      </div>
      <div>
        <p>{countB}</p>
        <button onClick={countUpB}>Bをカウントアップ</button>
      </div>
      <div>{hoge}</div>
    </div>
  );
};

export default AboutUseMemo;

解説

  • hogeを計算している関数呼び出しを、useMemoを使うように変更しました。
    • 第一引数は、関数呼び出しを行う
    • 第二引数は、依存配列を指定する。
      • 今回の場合は、countAのみ
  • ボタンを押下したときの挙動は…?
    • 「Aをカウントアップ」ボタンを押下すると、heavyFunctionが実行されます。
      • ここは問題なし。
    • 「Bをカウントアップ」ボタンを押下すると、heavyFunctionが実行されていません。
      • ボタンを押下したときにcountAについては、何も変化しないので、メモを変更する必要がないためです。

所感・・・

  • useMemoはこんな感じですかね…。
  • 次はuseCallbackを学ぼうかと思いますが、ざっと読んだ感じだとうまく使いこなせるか難しそうな予感です。

Reactの旅は続く!