🔖

useMemoを具体例とともに理解する

2023/09/23に公開

例えば、1 を 100000000回 足し上げるような関数を実行し、その計算結果を表示するコンポーネントがあるとする。

export const Counter = () => {
  // 1 を 100000000回 足し上げる
  const heavyComputation = () => {
    console.log('Computing...')
    let sum = 0;
    for (let i = 0; i < 100000000; i++) {
      sum += i;
    }
    return sum;
  }

  return (
    <p>計算結果:{heavyComputation()}</p>
  );
}

このコンポーネントをレンダリングしてみると、もちろん、 heavyComputation は実行されるため Computing... とログが出力される。

useMemoを使わない場合

ここで、このコンポーネントを ボタンをクリックすると state が変化するように変更する。

そうすると、ボタンをクリックするたびにこのコンポーネントは再レンダリングされるようになる。

export const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  // 1 を 100000000回 足し上げる
  const heavyComputation = () => {
    console.log('Computing...')
    let sum = 0;
    for (let i = 0; i < 100000000; i++) {
      sum += i;
    }
    return sum;
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment A</button>

      <p>計算結果:{heavyComputation()}</p>
    </div>
  );
}

ボタンをクリックした時の様子を確認してみると、ボタンをクリックするたびに Computing... とログが出力されていることからコンポーネントが再レンダリングされる度に heavyComputation が実行されていることがわかる。

useMemoを使う場合

このように何度実行しても計算結果が同じになるような関数がある時、この計算結果useMemoを使ってキャッシュすることができる。

// useMemo で計算結果をキャッシュする
const heavyComputation = useMemo(() => {
  console.log('Computing...')
  let sum = 0;
  for (let i = 0; i < 100000000; i++) {
    sum += i;
  }
  return sum;
},[]);

これで再度ボタンをクリックした時の様子を確認してみる。

そうすると state に変化が起きてコンポーネントが再レンダリングされているにも関わらず、 ログ出力は最初のレンダリング時にしか発生していない。

つまり、heavyComputationの実行は最初の1回だけ実行されていることがわかる。

このように、何度繰り返しても計算結果が同じになるような場合に useMemo を使うことで不要な関数実行を防ぐことができる。

Discussion