blog-hero-img

【React 19.2新機能】useEffectEventをビギナー向けにやさしく解説

pen-icon2025.10.9

この記事は約3分で読めます

Profile Pic

この記事の筆者:三好アキ


🟢 専門用語なしでプログラミングを教えるメソッドに定評があり、1200人以上のビギナーを、最新のフロントエンド開発入門に成功させる。
🟢『はじめてつくるReactアプリ with TypeScript』、『動かして学ぶ!Next.js/React開発入門(翔泳社/*韓国でも出版)』著者。


▼ Amazon著者ページはこちら
amazon.co.jp/stores/author/B099Z51QF2



React 19.2新機能【 useEffectEvent 】

10月1日にリリースされたReactバージョン19.2から、useEffectEventが使えるようになりました。

useEffectと名前がよく似ています。

これはuseEffectの問題点を解消する機能がuseEffectEventにはあるからです。

useEffectEventの機能を一言でいうと、「最新のprops/stateを参照できる」です。

ここから次の3つの具体的なメリットが出てきます。


• 依存配列の削減

• 不要なレンダリングの抑制

• ロジックの分離


本記事では、最初にuseEffectの問題点を確認し、そしてuseEffectEventを使うメリットを実際にコードで紹介していきます。

Reactビギナー 〜 中級者向けの内容なので、事前知識は不要です。

なお、Reactバージョン19.2で導入された<Activity>については、下記記事をご覧ください。


useEffectの問題点(簡単な説明)

useEffectのコードの構造を見てみましょう。

useEffect(() => {

    実行したい処理

}, [])       // ←依存配列

依存配列には、useEffect内で参照するstatepropsを入れます。

なぜ入れる必要があるかというと、useEffect内部に置かれた処理において、最新のstatepropsの値を利用できるようにするためです。

そのため、依存配列の中の値のどれか一つにでも変化があると、useEffectが実行されます。


しかし、依存配列内のstatepropsが変化してもuseEffectの実行は不要、というケースもあります。

不要なuseEffectの動きを抑制する一番簡単な方法は、「依存配列からstatepropsを取り除く」です。

確かにこれで不要なuseEffectの実行は回避できますが、その一方で、useEffect内に置かれた処理で最新のデータを参照できず、古いデータが使われ続けることになります。

とはいえ、このように言葉で説明していてもわかりづらいので、この点をコードで実際に確認してみましょう。

その中でuseEffectEventを使うメリットが見えてきます。

まずはReact + Viteのセットアップです。

準備(React + Vite)

ターミナルで次のコマンドを実行してください。

npm create vite@latest

質問がいくつか出てくるので、次のように答えてください。

Project name:
│  react-useeffectevent
│
◇  Select a framework:
│  React
│
◇  Select a variant:
│  JavaScript
│
◇  Use rolldown-vite (Experimental)?:
│  No
│
◇  Install with npm and start now?
│  No

インストールが完了したら、VS Codeでフォルダを開きましょう。


現時点(2025年10月9日)では、デフォルトでReactバージョン19.1がインストールされているので、これを19.2にアップデートします。

package.jsonを開き、reactreact-domのバージョンを次のように変更しましょう。

// package.json

    ...

    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^19.2.0",         // 変更
    "react-dom": "^19.2.0"      // 変更
  },
  "devDependencies": {
	...

変更を保存したら、インストールを実行します。

npm install

次に不要なファイルとコードを消します。

srcフォルダ内のApp.cssは削除しましょう。

次にApp.jsxindex.css内のコードをすべて消してください。

変更を保存したら、下記コマンドでReact + Viteを起動しましょう。

npm run dev

これで準備は完了です。

React 19.2の新機能useEffectEventを見ていきましょう。

useEffectの問題を実際に確認

まずは従来からあるuseEffectの動きを見て、問題を確認していきます。

App.jsxに次のコードを書いてください。

「ボタンを押す度にcountstateが一つずつ増えていく」というだけのコードです。

保存したら、ブラウザで動きを確認してみてください。

// App.jsx

import { useState } from "react"

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

    return (
        <div>
            <p>カウント数: {count}</p>
            <button onClick={() => setCount(count + 1)}>+ボタン</button>
        </div>
    )
}

export default App

次はここにuseEffectを書き足しましょう。

下記コードを書き足してください。

// App.jsx

import { useEffect, useState } from "react"  // 追加

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

    // ▼追加
    useEffect(() => {
        console.log("useEffectが実行されました")

        const timer = setTimeout(() => {
            alert(`現在のカウント数は ${count} です`)
        }, 5000)

        return () => clearTimeout(timer)
    }, [])
    // ▲追加

    return (
        <div>
            <p>カウント数: {count}</p>
            <button onClick={() => setCount(count + 1)}>+ボタン</button>
        </div>
    )
}

export default App

いま書いたコードを解説しましょう。

useEffectの最後にカラの依存配列([])があるので、このuseEffectは初回レンダリング時に一回だけ実行されるのがわかります。

そこで行われる処理は次の2つです。


console.log() ▶︎ useEffectの動きの確認のため

alert() ▶︎ カウント数を表示する


なおalert()は、setTimeout()で挟まれています。

setTimeout()の働きは遅延を引き起こすことです。

そのため、初回レンダリングから5秒後にalert()が実行されることになります。

そして最後のclearTimeout()はクリーンアップ(後片付け)のためです(これがないとsetTimeout()が意図通りに動かないことがあります)。

ブラウザで動きを確認してみましょう。

保存をしたらブラウザを開いてください。

image

5秒経つとalert()が表示されます。

image

次は、リロード(command + R)をしてください。

そして「+ボタン」を数回押しましょう。

5秒経つと再びalert()が表示されます。

image

しかしここで、少しおかしなことに気がつきます。

カウント数は上がっているのに、alert()上の数は0のままなのです。

image

理由を説明します。

これは、依存配列がカラで、useEffectが初回レンダリング時にしか動いていないためです。

そのため、ボタンが押されて数が増えたcountstateではなく、初回レンダリング時点の0countstate、つまり「古いstate」が参照されているのです。

この解決法は、「countstateが押される度にuseEffectを実行する」となります。

そうすれば最新のcountstateを参照できるでしょう。

countを依存配列に加えてください。

// App.jsx

import { useEffect, useState } from "react"

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

    useEffect(() => {
        console.log("useEffectが実行されました")

        const timer = setTimeout(() => {
            alert(`現在のカウント数は ${count} です`)
        }, 5000)

        return () => clearTimeout(timer)
    }, [count])    // 追加

    return (
        <div>
            <p>カウント数: {count}</p>
            <button onClick={() => setCount(count + 1)}>+ボタン</button>
        </div>
    )
}

export default App

変更を保存してブラウザを開いたら、「+ボタン」を数回押してください。

最後の押下から5秒経つとalert()が表示されます。

今回の数はカウント数と同じです。

image

ここでひとつ注目して欲しいのは、alert()の実行が「最後のボタン押下から5秒後」という点です。

これはuseEffectが、ボタン押下の度に実行されていることに由来します。

確認してみましょう。

開発者ツールから「console」を開いてください。

リロード(command + R)をしたら、ボタンを数回押しましょう。

すると次のように表示が出て、ボタン押下の度にuseEffectが動いているのがわかります。

image

しかし、このように毎回useEffectが実行されることはブラウザの負荷を高めます。

さらにuseEffectが毎回実行されることによって、alert()の表示も「最後のボタン押下から5秒後」となってしまっています。

依存配列にcountを加えた理由を思い出してください。

最新のcountstateを参照するためです。

countstateの最新状態を取得できるのであれば、useEffectは毎回実行されなくていいのです。

ここで使うのがuseEffectEventです。

useEffectEventで問題を解決する

まずはalert()の部分をuseEffect外部に切り出しましょう。

App.jsxのコードを次のように変更してください。

alert()の位置を変えただけなので、動きは先ほどと同じです。

// App.jsx

import { useEffect, useState } from "react"

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

    const showAlert = () => {
        alert(`現在のカウント数は ${count} です`)
    }

    useEffect(() => {
        console.log("useEffectが実行されました")

        const timer = setTimeout(() => {
            showAlert()
        }, 5000)

        return () => clearTimeout(timer)
    }, [count])

    return (
        <div>
            <p>カウント数: {count}</p>
            <button onClick={() => setCount(count + 1)}>+ボタン</button>
        </div>
    )
}

export default App

保存をしたらブラウザを見てください。

先ほども確認した次の2つのことがわかります。


alert()の実行は最後のボタン押下から5秒後

• ボタン押下の度にuseEffectが実行


ここでuseEffectEventを使いましょう。

次のように加えてください。

// App.jsx

import { useEffect, useState, useEffectEvent } from "react" // 追加

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

    const showAlert = useEffectEvent(() => {  // 追加
        alert(`現在のカウント数は ${count} です`)
    })   // 追加

    useEffect(() => {
        console.log("useEffectが実行されました")

        const timer = setTimeout(() => {
            showAlert()
        }, 5000)

        return () => clearTimeout(timer)
    }, [])           // 削除

    return (
        <div>
            <p>カウント数: {count}</p>
            <button onClick={() => setCount(count + 1)}>+ボタン</button>
        </div>
    )
}

export default App

依存配列からcountstateを消すのを忘れないようにしましょう。

保存したら、ブラウザで動きを確認してください。

注目して欲しいのは3点で、alert()の実行タイミング、alert()上のカウント数、そして「console」です。

image

useEffectは初回レンダリング時にしか動いていないにもかかわらず、正しいカウント数がalert()に表示されているのがわかります。

さらにalert()の実行タイミングも、「最後のボタン押下から5秒後」ではなく「初回レンダリングから5秒後」になっています。

useEffectEventを使うことで、useEffectを毎回実行させることなく、最新のcountstateを参照できるようになったのです。

さらに、ロジック部分を切り出したので、コードの見通しがよくなったこともボーナス的なメリットとして挙げられます。


useEffectEventを使うことで、依存配列の管理が楽になり、useEffectの不要な再実行を抑えることができます。

さらに、処理の具体的な中身(What to do)と、その処理の実行タイミング(When to do)を分離できます。

Reactバージョン19.2で追加されたもう一つの目玉機能<Activity>こちらの記事で紹介しているので、確認してください。

image

▼【無料フロントエンド・ガイド】は下記ページで受け取れます。

https://monotein.com/present-for-readers

Profile Pic

🟩 フロントエンド開発者入門ガイド【無料配布中】


最初にこれが知りたかった!
フロントエンド初心者が必ず押さえておきたい ― 『挫折しない勉強法』とその具体的ステップ、無料配布中。
(*名前不要・メールアドレスだけで受け取り可能です)