logo

React19.2で導入されたUseEffectEventの紹介

2025-11-16
2 months ago

開発環境

  • react 19.2.0
  • react-dom 19.2.0

前提

React 19.2 では useEffectEvent という新しいフックが導入されました。

これは 副作用内で参照するコールバックの安定性問題 を解決するための仕組みで、従来 useCallback や依存配列の調整で頑張っていた場面をシンプルにする目的があります。

特に以下のような課題を解決するためのフックです。

  • useEffect内で古い state 値を参照してしまう
  • イベントハンドラ(ユーザー操作)は常に最新の state にアクセスできるべき
  • しかしuseEffectは dependency の制御が難しい
  • 「イベント」と「副作用」が同じように扱われていたため、混乱が発生しやすかった

これらを 「Effect は Effect」「Event は Event」 として明確に分離するのが useEffectEvent の狙いです。

本題

UseEffectEvent とは

useEffectEventは、副作用内で使用するコールバックを「イベント」として宣言するためのフックです。

イベントとして宣言されたコールバックは「安定した参照」になるため、依存配列に入れる必要がなく、state の最新値にも常にアクセスできます。

import { useState, useEffect } from "react";
import { useEffectEvent } from "react";

function Example() {
  const [count, setCount] = useState(0);

  const onIntervalTick = useEffectEvent(() => {
    // 最新の count にアクセスできる
    console.log("count:", count);
  });

  useEffect(() => {
    const id = setInterval(() => {
      onIntervalTick();
    }, 1000);

    return () => clearInterval(id);
  }, []); // onIntervalTick を依存に書く必要がない

  return (
    <button onClick={() => setCount(c => c + 1)}>
      count: {count}
    </button>
  );
}

ポイントは・・・

  • onIntervalTick は常に最新の state を参照する
  • しかし参照は安定しており、useEffectの依存には含めない
  • 副作用の登録(setInterval)は一度きりでよい

従来のuseEffect+useCallbackでは実現が難しい構造がシンプルに書けるようになりました。

よくある問題の解決例

従来の問題:useEffect の依存配列が増え続ける

useEffect(() => {
  function handler() {
    console.log(value); // 最新値を参照したい
  }
}, [value]); // 毎回 effect が再走行してしまう

UseEffectEvent を使用

const handler = useEffectEvent(() => {
  console.log(value); // 最新値
});

useEffect(() => {
  window.addEventListener("mousemove", handler);

  return () => window.removeEventListener("mousemove", handler);
}, []); // handler を依存に含めなくて良い

結果・・・

  • イベントリスナーは 1 回だけ登録
  • しかし handler は常に最新の state を参照
  • 再レンダリングが減りパフォーマンスも改善

どんな場面で使うべきか

  • setInterval 内で state を参照したい
  • 外部 API のイベント監視(scroll, resize, WebSocket など)
  • effect の依存配列に入れたくないが、state の最新値は使いたい
  • useEffect の「無限ループ」対策に無理な回避策を書いていた場所

逆に使うべきではない例

  • 普通の UI イベント(onClick など)

 👉 通常の関数で十分。useEffectEventの対象ではない。

さいごに

useEffectEventは、「副作用」と「最新値を扱いたいコールバック」の扱いを分離するためのフックで、依存配列の管理や useCallbackの乱立といった煩雑さを大幅に解消します。

特に 外部イベントを扱うコンポーネントsetInterval / setTimeout が絡む処理 ではメリットが大きいです。React19.2 以降、useEffectの設計がより明確になり、複雑だったロジックが整理しやすくなりました。

参照