【React Hooks】useMemoでパフォーマンスを最適化しよう

Posted: 2021/2/26
React/
React Hooks

今回は React Hooks でパフォーマンスの最適化に用いられるuseMemoについて説明していきます!

useMemo とは

メモリを持ち、関数によってメモ化された値を返すフックです。まずメモ化とは何かを説明します。

メモ化

メモ化とは、関数の呼び出しで同じ入力が再度発生した時に、キャッシュした結果を返すことです。

メモ化された関数は特定の入力に対応する結果を記憶(キャッシュ)するため、そのキャッシュされた結果を再計算せずに返すことができます。よって 2 回目以降の同じ入力の関数呼び出しに対するコストが削減されます。

useMemo の定義

useMemoは先ほど説明した通りメモ化された値を返します。具体的には以下のように定義します。

const memorizedValue = useMemo(() => {
	// 何らかの複雑な処理
	...
}, [value]}

useEffectと同様に実行するコールバック関数とその依存配列を引数にとります(useEffect について知りたい方はこちらを見てください)。第二引数の依存配列の値が変更された場合のみ、値の再計算がされます。なお依存配列が渡されなかった場合は、レンダリング毎に新しい値が計算されてしまします。

そしてuseMemoはレンダー中に実行されるため、副作用などの処理はuseEffectにさせ、レンダリングに関係する処理のみを行いましょう。

useMemo を使ってパフォーマンスを向上させる例

以下のような関数コンポーネントを考えてみましょう。画面には入力欄と更新ボタンがあり、入力値に値を入れるとその値に+1000 して画面に表示してくれるようなコンポーネントです(実際にこのようなコンポーネントは作らないでしょうが)。ここではわざと+1000 する処理にループ処理を入れて、高コストな計算を再現しています。

import React, { useMemo, useState } from "react";

const highCostProcessing = (inputValue: number) => {
  let caliculateValue = Number(inputValue);
  for (let i = 0; i < 1000; i++) {
    caliculateValue += 1;
  }
  console.log("Finished");
  return caliculateValue;
};

const UseMemoSample: React.FC = () => {
  const [value, setValue] = useState(0);
  const [count, setCount] = useState(0);

  // Usage
  const memorizedValue = useMemo(() => {
    return highCostProcessing(value);
  }, [value]);

  return (
    <>
      <div>{memorizedValue}</div>
      <input type="text" onChange={e => setValue(e.target.value)} />
      <button onClick={() => setCount(count + 1)}>更新する</button>
    </>
  );
};

export default UseMemoSample;

このコンポーネントがレンダリングされた結果を見てみましょう。

useMemo

入力値が変わるごとにhighCostProcessingが呼ばれていることがわかります。ただ、ボタンがクリックされた時に state であるcountが変化していますが、useMemoのおかげで値の再計算を避けることができています。

具体的には以下のコードによる恩恵です。valueが依存配列に含まれているので、countが変化してもコールバック関数内部で呼ばれているhighCostProcessingは呼ばれず、キャッシュされた値を返しています。

const memorizedValue = useMemo(() => {
  return highCostProcessing(value);
}, [value]);

useMemo をいつ使うべきか

非常にコストのかかる計算を行う場合に使用してください。あまりコストのかからない計算をメモ化すると値を再計算するか判定する処理の方がコストがかかる場合があります。

まとめ

  • useMemo とはメモ化された値を返すフック
  • useMemo の第一引数にコールバック関数にコストのかかる計算をさせ、第二引数に依存配列を入れる
  • あまりコストのかからない計算をメモ化するとパフォーマンスに逆効果なので、コストがかなりかかる計算を行う場合のみメモ化するとよい