0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React における useCallback の依存関係と古いステートの罠

Posted at

React における useCallback の依存関係と古いステートの罠

React では、関数を useCallback でメモ化することで、無駄な再生成を防ぎ、パフォーマンスの最適化を行うことができます。しかし、依存配列を適切に指定しないと「古いステートを持ち続ける」という予期せぬ挙動を引き起こすことがあります。


🔁 問題の例

以下のコードを見てください:

const Component = () => {
  const [count, setCount] = useState(0);

  const funcA = useCallback(() => {
    console.log('count in funcA:', count);
  }, [count]); // ✅ count に依存している

  const funcB = useCallback(() => {
    funcA(); // 古い funcA が使われる可能性
  }, []); // ⚠️ funcA を依存配列に含めていない

  return (
    <div>
      <button onClick={funcB}>Click</button>
      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
    </div>
  );
};

このコードでは以下の問題が起きます。

  • funcAcount に依存しており、count が更新されるたびに新しい関数になります。
  • しかし funcB は依存配列が空なので、一度生成された funcA をそのまま使い続けます。
  • その結果、funcB の中で使われる funcA古いステート(count)にバインドされたまま になります。

✅ 要点まとめ

項目 状況 結果
funcAcount を依存登録 ✅ 正しい
funcBfuncA を依存登録しない ⚠️ 古い funcA を呼び続ける

関数Bの中で使っている関数Aが新しくなっていても、関数Bが古いAを保持している場合、最新の状態を取得できない。

これは React のクロージャの性質と useCallback の依存配列の指定方法に由来するものです。


🛠 対策

1. funcB の依存配列に funcA を追加する

const funcB = useCallback(() => {
  funcA();
}, [funcA]); // ✅ funcA が更新されるたびに funcB も再生成

2. そもそも useCallback を使わない

パフォーマンスの最適化が不要な場合、useCallback を使わずにそのまま関数を定義しても問題ないケースも多いです。


💡 まとめ

  • useCallback を使うときは 依存配列が命
  • 呼び出す関数を依存配列に入れ忘れると、古いバージョンの関数を使い続けることになる
  • useCallback による最適化は便利ですが、クロージャによる副作用に注意が必要です。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?