Tech Starlog

React useEffect

投稿日:2026/02/16

本記事では、Reactの重要なHookである useEffect について解説します。


1. useEffectとは?

useEffectは、副作用(Side Effect)を扱うためのHookです。

副作用とは?

Reactでは「画面を作る処理(レンダリング)」以外の処理を副作用と呼びます。

例えば:

  • API通信(データ取得)
  • タイマー処理(setInterval)
  • イベントリスナー登録
  • DOMの直接操作
  • ローカルストレージ操作

なぜ分けるの?

Reactは「UIを作ること」に集中する仕組みです。 そのため、画面描画と外部処理を分離する設計になっています。


2. 基本構文

import { useEffect } from "react";

useEffect(() => {
  // 実行したい処理
}, []);

構造は次の通りです。

useEffect(実行する関数, 依存配列);

第2引数「依存配列」とは?

「どの値が変わったら再実行するか」を指定する場所です。

これがuseEffect理解の最大のポイントです。


3. 実行タイミングの違い

① 毎回実行される

useEffect(() => {
  console.log("毎回実行");
});

→ レンダリングのたびに実行されます。

⚠️ 注意:多くの場合これは意図しない動作になります。

② 初回のみ実行(マウント時)

useEffect(() => {
  console.log("初回のみ実行");
}, []);

→ 空配列 [] の場合、最初の1回だけ実行されます。

主な用途:

  • API通信
  • 初期設定
  • 初回データ取得

③ 特定の値が変わった時だけ実行

useEffect(() => {
  console.log("countが変わった");
}, [count]);

count が変わった時のみ実行されます。

つまり、

「countが更新されたらこの処理を実行する」

という意味になります。


4. API通信の例

import { useState, useEffect } from "react";

function UserList() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then(res => res.json())
      .then(data => setUsers(data));
  }, []);

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

なぜ [] をつけるの?

もし依存配列を書かなければ、

  1. データ取得
  2. setUsers実行
  3. 再レンダリング
  4. またfetch実行

という無限ループになります。

そのため、API通信は空配列が基本です。


5. クリーンアップ処理

useEffectは「後片付け」も書けます。

useEffect(() => {
  const timer = setInterval(() => {
    console.log("1秒ごと");
  }, 1000);

  return () => {
    clearInterval(timer);
  };
}, []);

なぜ必要?

もしクリーンアップを書かないと、

  • タイマーが増え続ける
  • イベントが重複登録される
  • メモリリークが発生する

といった問題が起きます。

よく使うケース

  • setInterval
  • addEventListener
  • WebSocket
  • サブスクリプション処理

6. よくあるミス

❌ 無限ループ

useEffect(() => {
  setCount(count + 1);
}, [count]);

なぜ無限ループになるの?

  1. countが変わる
  2. useEffectが実行される
  3. setCountでcountが更新される
  4. またuseEffectが実行される

→ 永遠に繰り返す

❌ 依存配列を書き忘れる

useEffect(() => {
  console.log(data);
}, []);

→ dataが変わっても再実行されない

初心者は「とりあえず[]を書く」ことがありますが、 本当に初回だけで良いか考えることが重要です。


7. 実務での考え方

① 副作用かどうかを考える

次の質問をしてみてください:

「これはUIを作る処理か?」 「外部とのやり取りか?」

外部処理ならuseEffectです。

② 依存配列は正確に書く

ESLint(react-hooks/exhaustive-deps)に従うのが基本です。

無理に消さないことが重要です。

③ 複雑ならカスタムフックに分離

function useUsers() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch("/api/users")
      .then(res => res.json())
      .then(setUsers);
  }, []);

  return users;
}

ロジックを分離すると、 コンポーネントがスッキリします。


8. useEffectの本質

useEffectは

「レンダリングが終わった後に実行される処理」

を管理する仕組みです。

Reactの流れ

  1. state変更
  2. コンポーネント再実行(再レンダリング)
  3. DOM更新
  4. useEffect実行

重要なのは、

useEffectは描画後に実行される

という点です。


9. 実行順

基本の流れ

  1. state更新
  2. 再レンダリング
  3. DOM更新
  4. useEffect実行

クリーンアップがある場合

  1. state更新
  2. 再レンダリング
  3. 前回のクリーンアップ実行
  4. DOM更新
  5. 新しいuseEffect実行

ポイント:

「次のEffectが実行される前に、前回が片付けられる」

React18 StrictModeの場合

開発環境では安全性確認のため

  1. useEffect実行
  2. クリーンアップ
  3. もう一度実行

が起きます。

これはバグではありません。

本番環境では1回のみです。


まとめ

  • useEffectは副作用を扱うHook
  • 依存配列が最重要ポイント
  • API通信は空配列が基本
  • クリーンアップは必須
  • 無限ループに注意