useCallbackの使い方を徹底解説!ReactHooks講座【初心者向け】

はじめに

Reactを書いていると、「このコンポーネント、何回も無駄に動いてない?」って気になることありませんか?
それ、**useCallback**を使えば解決できます!
この記事では、コード例を交えながら「どう使うのか」「なぜ便利なのか」を、初心者の方にも分かりやすく説明します。


useCallbackってなに?

useCallbackは関数を再利用するためのReactフックです。

Reactのコンポーネントは、状態が変わるたびに全部再描画されるので、
普通に関数を定義すると、何度も新しい関数が作られちゃいます。

でも、useCallbackを使うと、必要なときだけ関数を更新して、
それ以外は「前に作ったやつそのまま使おう!」ってできます。


基本構文

const memoizedCallback = useCallback(
  () => {
    // コールバック関数の内容
  },
  [依存関係]
);
  • 第一引数: メモ化したい関数。
  • 第二引数: 関数を再生成する条件となる依存関係の配列。

useCallbackを使う理由

再レンダリングを防ぐ

通常、Reactの関数コンポーネントでは毎回新しい関数が作られます。例えば以下のようなコードを考えてみましょう。

const Child = React.memo(({ onClick }) => {
  console.log("Child is rendering!");
  return <button onClick={onClick}>Click me</button>;
});

function App() {
  const [count, setCount] = React.useState(0);

  const handleClick = () => {
    console.log("Button clicked");
  };

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Child onClick={handleClick} />
    </div>
  );
}

この場合、Appが再レンダリングされるたびに新しいhandleClick関数が生成されるため、Childも再レンダリングされてしまいます。ここでuseCallbackを使うとどうなるでしょう?

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

useCallbackを使うことで、handleClickは常に同じ関数オブジェクトを保持し、React.memoと組み合わせることでChildの再レンダリングを防ぐことができます。


React.memoとの連携

React.memoはコンポーネントをメモ化して、propsが変更されない限り再レンダリングを防ぎます。しかし、渡されるpropsが新しいオブジェクトや関数である場合、React.memoの効果が消えてしまいます。

React.memoを組み合わせると…。

const Child = React.memo(({ onClick }) => {
  console.log("Child is rendering!");
  return <button onClick={onClick}>Click me</button>;
});

function App() {
  const [count, setCount] = React.useState(0);

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

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Child onClick={handleClick} />
    </div>
  );
}

これにより、handleClickが常に同じオブジェクトを保持し、React.memoが正常に動作します。


第二引数の重要性

useCallbackの第二引数(依存関係の配列)は、関数が再生成されるタイミングを決定します。この依存関係に基づいて、必要な場合だけ関数を新しく生成します。

依存関係が空の場合

const handleClick = useCallback(() => {
  console.log("Button clicked");
}, []);
  • 効果: handleClickは一度だけ生成され、それ以降再生成されません。
  • 適用例: 外部の状態や値を参照しない関数。

依存関係がある場合

const handleClick = useCallback(() => {
  console.log("Count is: ", count);
}, [count]);
  • 効果: countが変更されたときのみ、新しい関数が生成されます。
  • 適用例: 関数内でcountなどの外部の値を参照する場合。

依存関係が適切に設定されていないと、最新の値を参照できなかったり、不要なレンダリングが発生する可能性があります。


関数を渡すときの注意点

useCallbackを使うべき場面とそうでない場面があります。

使うべきケース

  • 子コンポーネントに関数をpropsとして渡す場合。
  • 再レンダリングが頻繁に発生する場面で、パフォーマンスを最適化したい場合。

過剰に使わない

useCallbackを使いすぎるとコードが複雑になり、逆にメモ化コストでパフォーマンスが低下することもあります。


実用例:フィルタリング機能

以下は、useCallbackを使った実際のアプリケーションの例です。

function App() {
  const [items, setItems] = React.useState([1, 2, 3, 4, 5]);
  const [filter, setFilter] = React.useState("");

  const filteredItems = React.useMemo(() => {
    return items.filter(item => item.toString().includes(filter));
  }, [items, filter]);

  const handleChange = useCallback((event) => {
    setFilter(event.target.value);
  }, []);

  return (
    <div>
      <input onChange={handleChange} placeholder="Filter items" />
      <ul>
        {filteredItems.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

まとめ

useCallbackは、Reactアプリケーションのパフォーマンスを向上させるための重要なツールです。特に、React.memoと組み合わせることで、子コンポーネントの不要な再レンダリングを防ぐ効果があります。

  • React.memo: 子コンポーネントのメモ化。
  • useCallback: 関数のメモ化。
  • 第二引数: 関数の再生成をコントロール。

公式ドキュメントも参考にしてください!


関連する記事はこちら↓↓

タイトルとURLをコピーしました