Tyotto good!

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

Posted: February 25, 2021

今回は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;

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

入力値が変わるごとにhighCostProcessingが呼ばれていることがわかります。ただ、ボタンがクリックされた時にstateであるcountが変化していますが、useMemoのおかげで値の再計算を避けることができています。
具体的には以下のコードによる恩恵です。valueが依存配列に含まれているので、countが変化してもコールバック関数内部で呼ばれているhighCostProcessingは呼ばれず、キャッシュされた値を返しています。

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

useMemoをいつ使うべきか

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

まとめ

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