第2回

useEffectの基本:外部との同期・依存配列・クリーンアップ

ページタイトルを同期する完成サンプルでuseEffectの役割を学びます。イベント処理との違い、依存配列、クリーンアップ、StrictModeでの確認方法を解説します。

·6分で読める

制作・運営:React Guide 運営者

Effectが必要になる境界

useEffect は、Reactの表示を外部の仕組みと同期させるHookです。タイマー、購読、ブラウザAPIなど、コンポーネントを表示している間に接続しておきたい相手があるときに使います。

計算できる値をstateへコピーする用途や、クリック時の送信処理には、まずEffectを使わない実装を考えます。

やりたいこと 置く場所
商品数×単価を表示する レンダー中の計算
送信ボタンを押したら保存する イベントハンドラー
表示中のページ名をdocument.titleに反映する Effect
表示中だけタイマーを動かす Effectとcleanup

ページ名をブラウザのタブに反映する

以下は src/App.tsx を置き換えて試せる例です。React 19系のVite React+TypeScriptプロジェクトを使います。

import { useEffect, useState } from 'react'

function PageTitle({ title }: { title: string }) {
  useEffect(() => {
    const previousTitle = document.title
    document.title = title
    return () => { document.title = previousTitle }
  }, [title])

  return <h1>{title}</h1>
}

export default function App() {
  const [title, setTitle] = useState('学習メモ')
  const [visible, setVisible] = useState(true)
  return (
    <main>
      <label>ページ名<input value={title} onChange={e => setTitle(e.target.value)} /></label>
      <button onClick={() => setVisible(v => !v)}>表示切り替え</button>
      {visible && <PageTitle title={title} />}
    </main>
  )
}

title を読んでいるので依存配列は [title] です。ここを [] にすると、入力欄を変更してもタブの文字は最初のままになります。元のタイトルへ戻すcleanupは、この例のように1つのコンポーネントがタイトルを管理するときのものです。複数の部品で同じdocument.titleを同時に管理しないでください。

いつ実行されるか

指定 実行される条件
依存配列なし コンポーネントの各コミット後
[] マウント時。依存値の変更による再実行はない
[title] マウント時と、titleがObject.isで異なるコミット後

依存値が変わると、古い値でcleanup、新しい値でsetupの順に実行します。アンマウント時にもcleanupします。開発時のStrictModeでは初期のsetup→cleanup→setupを追加で試す場合があります。「一生に1回だけ実行する」保証ではありません。

Effectはサーバーレンダリング中には動きません。また「コミット後」と「必ずブラウザが描画し終えた後」は同じではありません。操作に起因するEffectはpaintより前に動く場合もあります。

データ取得も外部との同期

Effect内でfetchする場合、初回のデータがない表示、HTTPエラー、取得中のID切り替えを扱う必要があります。コードを短くするためにこれらを外したものを、完成版として使わないでください。

フレームワークのloaderなどで取得できる場合は、その仕組みも検討します。Effectでの取得は、すべてのReactアプリに必須の方法ではありません。

自分で確認する

  1. 入力欄を「買い物メモ」に変更し、見出しとブラウザのタブが両方変わるか確認します。
  2. 表示切り替えでPageTitleを外し、タブが元の文字に戻るか確認します。
  3. ローカルでだけ依存配列を [] に変え、入力後にどちらが更新されなくなるか予測して試します。確認後は [title] に戻します。

React公式:useEffect、Effectが不要なケース

#react#hooks#useEffect#intermediate