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