🎫

【初心者向け】useEffectEventが少しわかるようになる記事

に公開

まずこの記事を読む前に....

必ずこちらを一読しましょう
https://react.dev/reference/react/useEffectEvent

余談ですが、Hooksってたくさんあって初心者の人ってわけわからんくなりますよね。
こういうのを学習する際のポイントは、一気に全部理解しようとする必要はないと思っていて、特に慣れてない人はポイントと目的を明確にしてドキュメントを読むことからスタートすればいいと思います。

  1. 何のために提供されてるのか?
  2. それを使うことで得られるメリットは何なのか?
  3. それがあるのとないのとでは何が違うのか?

若干意味が被ってるようにも見えますが、まあ各々で目的を明確にしましょうということで、ドキュメントに沿って解説していきたいと思います。

useEffectEventはどういう時に使うの?

一言で言うと
「最新の値を使いたいけど、その値が変わってもEffectを再実行したくない」時に使う
うん、なるほど。わからん。となった方、気にしないで読み進めていきましょう。

なぜ必要?🤔

まず、useEffectの基本ルールですが...
useEffectは実行タイミングを理解していないと思わぬ罠にハマったり、使用しなくていい箇所で使用してしまうので、さらに理解したい方はこちらの記事がとてもわかりやすいです。必ず読みましょう。
https://zenn.dev/yumemi_inc/articles/react-effect-simply-explained

一旦、超簡単に解説(以降useEffectの解説自体は端折ってますので、上記の記事を何度も見返すとよ良いです)

useEffect(() => {
  // ここで使うuseEfect外部のリアクティブな値を依存配列に入れる、いや、入れないといけない
}, [依存配列]);

「リアクティブな値」ってなんだよってなった方向けに、ここでは「コンポーネントが再レンダリングされると変わる可能性がある値」としておきます。

初学者さんは特にですがESLintのエラー無視して、この値が変化した時にはuseEffect発火してほしくないから、依存配列に値を含めないようにしようとかはやめましょう。そもそもその考え方自体がuseEffectの使用用途に沿ったものではないので、再度、下記ドキュメントや紹介した記事を読むようにしてください📚

ドキュメントはこちら
https://react.dev/reference/react/useEffect

こんな状況を想定してみましょう(公式ドキュメントから)

function ChatRoom({ roomId, theme }) {
  const [message, setMessage] = useState('');
  
  useEffect(() => {
    const connection = connectToChat(roomId);
    
    connection.on('connected', () => {
      // 接続時に通知を表示したい
      showNotification('接続しました!', theme);
    });
    
    connection.connect();
    return () => connection.disconnect();
  }, [roomId, theme]); // ❌ themeも依存配列に入れないといけない
  
  // ...
}

ここでの問題点は...

  • theme(テーマカラー)が変わるたびに、チャットを切断→再接続してしまう
  • 本当はroomIdが変わった時だけ再接続したい
  • でもtheme最新の値は使いたい

useEffectEventが解決💡

function ChatRoom({ roomId, theme }) {
  // ここでEffectEventを作成する
  const onConnected = useEffectEvent(() => {
    // ここではthemeの最新値が使える
    showNotification('接続しました', theme);
  });
  
  useEffect(() => {
    const connection = connectToChat(roomId);
    
    connection.on('connected', () => {
      onConnected(); // EffectEventを呼ぶ
    });
    
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]); // ✅ roomIdだけでOK
  
  // ...
}

何が起きてる?

  1. themeが変わっても、Effectは再実行されない
  2. でもonConnectedが呼ばれた時は、**その時点の最新のtheme**が使われる
  3. チャットの再接続はroomIdが変わった時だけ

例えるなら

他にいい例えありそうですが...

useEffect = 「監視カメラ」

  • 監視対象(依存配列)に変化があると、必ず作動する
  • 見張るものが増えると、無駄に作動してしまう

useEffectEvent = 「スナップショット」

  • 呼ばれた瞬間に、その時の最新情報を自動的に記録してくれる
  • でも監視カメラの監視対象には含まれない

注意点

  1. Effectの中でしか呼べない
// ❌ ダメ
<button onClick={onConnected}>接続</button>

// ✅ OK
useEffect(() => {
  onConnected();
}, [dependency]);
  1. 他のコンポーネントに渡せない
// ❌ ダメ
<ChildComponent callback={onConnected} />

まとめ

useEffect useEffectEvent
目的 副作用を実行 最新値を読むだけ
再実行 依存値が変わると再実行 依存値が変わっても影響なし
値の取得 定義時の値 常に最新値
使い所 変化に反応したい 最新値だけ欲しい

Discussion