useEffect

JS

useEffectはReactコンポーネントが表示された後に実行される関数を登録するための仕組みです。

import { useEffect } from "react";

function MyComponent() {
  useEffect(() => {
    console.log("この中の処理は、画面に表示された後に実行されるよ!");
  }, []);

  return <div>Hello</div>;
}

このコンポーネントの実行順:

  1. MyComponent() 関数が呼ばれる
    • JSX (<div>Hello</div>) を返す
  2. ReactがこのJSXをDOMに描画する
    • <div>Hello</div> がブラウザの画面に表示される!
  3. 表示が終わった“あとで” useEffect() の中が実行される
    • console.log("画面に表示されたあと!") が出力される ✅

つまり、return で JSX を返すことで 「何を表示するか」 が決まり、その 表示が終わったタイミングで useEffect() が発動します。

引数は2つあり、依存配列によってタイミングが変わります。

useEffect(実行したい関数, 依存配列);
書き方いつ実行されるか
useEffect(() => { ... }, [])初回マウント時(1回だけ)
useEffect(() => { ... }, [count])count が変化したとき
useEffect(() => { ... })毎回(レンダーのたびに)

クリーンアップ関数

イベントリスナーをuseEffectの中で登録したら、クリーンアップをセットで書くのが基本です。

useEffect(() => {
  // ① なにか副作用の処理(例えばイベント登録とか)
  window.addEventListener("resize", handleResize);

  // ② return でクリーンアップ関数を書く!
  return () => {
    // これが「後片付け」!
    window.removeEventListener("resize", handleResize);
  };
}, []);

クリーンアップされるタイミングは、

コンポーネントが画面から消えたとき(アンマウント)

useEffectの依存配列の値が変わって再実行されるとき

です。

アンマウントとは

function App() {
  const [show, setShow] = useState(true);

  return (
    <div>
      <button onClick={() => setShow(!show)}>切り替え</button>
      {show && <Message />}
    </div>
  );
}

function Message() {
  useEffect(() => {
    console.log("マウントされたよ!");

    return () => {
      console.log("アンマウントされたよ!");
    };
  }, []);

  return <p>こんにちは!</p>;
}
  1. 最初 showtrue なので <Message /> が表示される → マウント(表示)
  2. ボタンを押して showfalse になると <Message /> は消える → アンマウント(非表示)
タイミング意味
マウントコンポーネントが画面に「表示された」瞬間
アンマウントコンポーネントが「画面から消えた」瞬間

クリーンアップ関数が実行されるタイミング

上の例は依存配列が空なので、クリーンアップ関数が実行されるのはアンマウントされる時になります。

では、依存配列がある場合はというと、

  • 依存配列が変わった時
  • アンマウント時

になります。

よく使うケース

ケース解説
データの取得fetch()axios でAPI通信コンポーネントの初回マウント時に実行される
イベントリスナーの登録/解除window.addEventListener(...)登録とクリーンアップが必要なとき
タイマーの設定/解除setTimeout, setInterval一定時間後に何かする、ループ処理など
依存する値の変更に反応ある state や props が変わったときに何かするフォーム入力、フィルター変更など

データの取得

useEffect(() => {
  const fetchData = async () => {
    const res = await fetch('https://api.example.com/data');
    const json = await res.json();
    console.log(json);
  };

  fetchData();
}, []); // 初回マウント時のみ

入力内容が変わったらAPIで自動補完

import { useState, useEffect } from 'react';
import axios from 'axios';

function SearchForm() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  useEffect(() => {
    if (!query) return;

    const fetchResults = async () => {
      try {
        const res = await axios.get(`/api/search?q=${query}`);
        setResults(res.data);
      } catch (e) {
        console.error('検索失敗:', e);
      }
    };

    fetchResults();
  }, [query]); // ← 入力が変わるたびに実行

  return (
    <>
      <input
        type="text"
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="キーワード入力"
      />
      <ul>
        {results.map(r => <li key={r.id}>{r.name}</li>)}
      </ul>
    </>
  );
}