🐭 useCallbackとuseMemo
作成日: 2021/12/24
3

useCallbackについて

普通に関数コンポーネント上に関数宣言を書いておくと、レンダリングのたびに関数が再生成されることになるがこれが余分な処理になるので、これを防ぐ仕組みがuseCallback。

useCallbackもuseEffectと似ていて依存変数の配列を渡す形になる。
配列で渡されたステートが変更された時にコールバックの再評価を行って関数を再生成する
つまり、
配列で渡してあげた状態が変わらない限り、関数が再生成されないようにしてくれる
useEffectはプログラムの実行タイミングを見ている一方でuseCallbackは関数定義されているもの自体を新たに作り出すといった感じでいいかな。

const onClick = useCallback(([コールバック], [依存変数の配列]) => {
 // stateAが変更されたらこの関数部分が再生成される
},[stateA]);

例えば

const onChangeDirection = useCallback(
  (newDirection) => {
    if (status !== GameStatus.playing) {
      return;
    }
    if (OppositeDirection[direction] === newDirection) {
      return;
    }
    setDirection(newDirection);
  }, [direction, status]);

のようにdirectionstatusを配列で渡している場合、これらが変更された時だけonChangeDirectionが再生成されることになる。

使いどころは、レンダリングのたびに関数が再生されるのを防ぎ、配列が変更された時だけ関数が再生成されるようにしたい時。ということ

useMemoについて

あくまでも値を保存するために使われるらしい。
計算量の多い値を保持する必要があり、レンダリング毎の再計算を避けたい時に使うようにする。
useCallbackのデータ用のフックで何か重い計算を行ってそれを表示していた場合に、レンダリングのたびにそれを再計算するのは非効率。そのため、useMemoを使って配列で渡したステートが変わらない限り同じ値を使いまわすということが出来る。

useMemo([コールバック], [依存変数の配列]);
//コード例
const memoizedList = useMemo(() => {
  return list.filter((item) => {
    return item % 2 === 0;
  });
}, [list]);

上記のコード例だと list が書き換わらない限りは memoizedList は再計算を行わずパフォーマンスを最適化できる。

const List = ({ list }) => {
  const memoizedList = useMemo(() => {
    return list.filter(((num) => num % 2 === 0)
  }, [list]);
  return (
    <ul>
      {
        memoizedList.map(num => {
          return <li>{num}</li>
        })
      }
    </ul>
  )
}