BLOG

ブログ

いまさらuseCallbackを理解したい

reactを触っているとよくわからんhooksランキング上位に入ると思います。

なので今更ですが復習してみましょう。

子コンポーネントの不要な再レンダリングを防ぐ

そんな感じのhooksです。とはいえ言葉で言われてもよくわからないのでコードで見てみましょう

useCallbackなし

import { useState, memo } from "react";

// 子コンポーネント
const Child = memo(({ onClick }: { onClick: () => void }) => {
  console.log("Childコンポーネントがレンダーされました");
  return <button onClick={onClick}>子ボタン</button>;
});

export default function App() {
  const [count, setCount] = useState(0);

  const handleClick = () => console.log("clicked!");

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>親ボタン +1</button>
      <Child onClick={handleClick} />
    </div>
  );
}

この状態で子ボタンを押下した時のログは以下のようになります。

Childコンポーネントがレンダーされました
clicked!

さらに親ボタンを押下するとどうでしょうか?「Childコンポーネントがレンダーされました」がまた出てきます。

Childコンポーネントがレンダーされました
clicked!
Childコンポーネントがレンダーされました

useCallbackあり

import { useState, useCallback, memo } from "react";

// 子コンポーネント
const Child = memo(({ onClick }: { onClick: () => void }) => {
  console.log("Childコンポーネントがレンダーされました");
  return <button onClick={onClick}>子ボタン</button>;
});

export default function App() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("clicked!");
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>親ボタン +1</button>
      <Child onClick={handleClick} />
    </div>
  );
}

子ボタンを押下した時のログは以下のようになります。この点まではuseCallbackを使わないのと同じ。

Childコンポーネントがレンダーされました
clicked!

しかし、親ボタンを押してもログには何も追加されません。

子コンポーネントが再レンダリングされないということです

Childコンポーネントがレンダーされました
clicked!

解説

  • 子コンポーネントで毎回同じ関数が生成されるので子コンポーネントが毎回レンダリングされてしまう。
  • つまりuseCallbackのあるなしで不要なレンダリングが発生することがある。
  • 依存配列が変わらない限り 同じ関数オブジェクトを再利用 できる
  • 結果として、子コンポーネントの props が「毎回新しくなった」とは見なされず、React.memo と組み合わせれば 無駄な再レンダーを防止できる

useCallbackなし

このように、親コンポーネントに更新があると追随して子コンポーネントも再レンダリングがかかる

これをuseCallbackを使うことで、必要な親コンポーネントのみが更新され、子コンポーネントは再レンダリングを行わないようにすることができる。

つまり、不要なレンダリングをせずに画面描画速度の上昇や、パフォーマンスを向上することができます

まとめ

  • 子コンポーネントに渡される関数にuseCallbackを使用することでReactは同じ関数を再利用する。よって毎回関数を作り直す必要がなくなり、パフォーマンスが向上
  • 不要な再レンダリングがされないため、子コンポーネントに安定性に寄与
  • 特に関数をpropsとして渡す場面において有効

RELATED ARTICLE