Skip to content

【React学習9】useCallbackについて

Published: at 00:00

ReactのuseCallbackについて学習した。

Table of contents

Open Table of contents

useCallbackとは

useCallbackは、依存値が変更されない限り、同じ関数オブジェクトを再利用するためのフック。 不要な関数の再生成を防ぐことで、パフォーマンスを向上させることができる。 Reactでは、コンポーネントの再レンダリングされるたびに、その中で定義した関数も新たに生成される。 useCallbackを利用すると、依存値が変更されない限り同じ関数オブジェクトを再利用できる。 useCallbackだけでは子コンポーネントの再レンダリングは防げない。memoと組み合わせることで効果を発揮することが多い。

useCallbackの基本的な書き方

基本的な記述方法は下記の通り。

const handleClick = useCallback(() => {
  処理
}, []);

useCallbackの役立つ場面

親コンポーネントで定義した関数を子コンポーネントに関数を渡す場合、親コンポーネントが再レンダリングされるたびに、新しい関数オブジェクトが生成される。 その結果、子コンポーネントから見るとpropsが変更されたと判断され、再レンダリングが発生する。

useCallbackを使うことで、親コンポーネントが再レンダリングされても、依存値が変更されない限り同じ関数オブジェクトを再利用できる。

useCallbackの使い方

簡単な実例。クリックすると、console.logが出力される。

import { useCallback } from "react";

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

  return (
    <div>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
};

export default MyComponent;

親コンポーネントから子コンポーネントへ渡す例。

最初の読み込み時にchild renderが表示される。 Parent Updateを押すと、再レンダリングが発生し、Countが更新されるが、child renderは表示されない。 click meを押すと、handleClickが呼ばれ、clickedがコンソールに出力される。

親コンポーネントから子コンポーネントへhandleClickを渡す。 親コンポーネント側でChildComponentをimportし、onClickhandleClickを渡す。

子コンポーネント側では、memoを使う。 memoはpropsが変更されていない場合、コンポーネントの再レンダーをスキップすることが可能。 上記の場合、親コンポーネントが再レンダリングされても、useCallbackによってhandleClickの参照が維持されるため、propsが変更されず、memoによって子コンポーネントの再レンダリングをスキップすることができる。

親コンポーネント

import { useCallback, useState } from "react";
import ChildComponent from "./ChildComponent";

const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const handleClick = useCallback(() => {
    console.log("clicked");
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((prev) => prev + 1)}>Parent Update</button>
      <ChildComponent onClick={handleClick} />
    </div>
  );
};

export default ParentComponent;

子コンポーネント

import { memo } from "react";

type Props = {
  onClick: () => void;
};

const ChildComponent = memo(({ onClick }: Props) => {
  console.log("child render");
  return (
    <div>
      <button onClick={onClick}>Click me</button>
    </div>
  );
});

export default ChildComponent;

注意点

軽量なコンポーネントや頻繁な更新が発生しない場合は、使用しない方が良い。 コードが煩雑になり、メンテナンスが難しくなる可能性がある。

まずはuseCallbackは使用せず実装し、子コンポーネントへ関数をpropsとして渡し、その子コンポーネントをmemo化している場合などに利用すると効果がある。

まとめ

useCallbackuseMemoを利用することで、不要な再生成や再計算を避け、パフォーマンス改善が期待できる。 ただし、不必要なところに使用するとコードが煩雑になり、メンテナンスも難しくなるので、「どこで使用するか」は状況を見て、子コンポーネントへ関数をpropsとして渡しているか、memoと組み合わせて効果があるかなどを判断する必要がある。