useEffectとは
useEffectは、Reactコンポーネントで「副作用(Side Effect)」を実行するためのフックです。
💡 副作用(Side Effect)とは?
副作用とは、コンポーネントのレンダリング以外で行われる処理のことです。 例えば、API呼び出し、タイマー設定、DOM操作、ログ出力などが副作用に当たります。
🎯 例えで理解しよう
🍽️ レストランの例: useEffectは「お客様が座った後に、注文を取って、料理を運ぶ」ようなものです。 画面に表示された後(コンポーネントがレンダリングされた後)に、必要な処理を実行します。
📞 電話の例: useEffectは「電話が繋がった後に、用件を伝える」ようなものです。 コンポーネントが表示された後に、外部との通信や処理を行います。
⏰ タイマーの例: useEffectは「時計が動き始めた後に、定期的に時刻を更新する」ようなものです。 コンポーネントが表示された後に、継続的な処理を開始します。
🍽️ 身近な例えで理解しよう:レストランの例
レストランの流れ
- 1. お客様が席に座る(コンポーネント表示)
- 2. ウェイターが注文を取る(useEffect実行)
- 3. 料理を運ぶ(副作用処理:API呼び出しなど)
- 4. お客様が帰る時に片付ける(クリーンアップ)
useEffectの流れ
- 1. コンポーネントが表示される(マウント)
- 2. useEffectが実行される
- 3. 副作用処理を実行(API、タイマーなど)
- 4. コンポーネント削除時にクリーンアップ
💡 useEffectは「お客様が座った後に注文を取り、料理を運ぶウェイター」のようなものです
✅ useEffectを使う理由
- API呼び出し: データを外部サーバーから取得できます
- タイマー処理: 定期的に何かを実行できます(例:時計、カウントダウン)
- DOM操作: ブラウザのAPIを使って、ページタイトルを変更したり、スクロール位置を設定したりできます
- イベントリスナー: ウィンドウのサイズ変更などのイベントを監視できます
基本的な使い方
useEffectの基本的な書き方を学びましょう。
📝 useEffectの基本構文
import { useEffect } from "react";
const MyComponent = () => {
// useEffectの基本的な書き方
useEffect(() => {
// ここに副作用の処理を書く
console.log("コンポーネントが表示されました!");
});
return <div>Hello World</div>;
};1. useEffectのインポート: ReactからuseEffectをインポートします
2. useEffectの呼び出し: コンポーネント内でuseEffectを呼び出します
3. 処理の記述: 第1引数として、実行したい処理を関数で渡します
4. 実行タイミング: デフォルトでは、コンポーネントがレンダリングされるたびに実行されます
⚠️ 重要な注意点
- 依存配列を指定しない場合、毎回のレンダリング後に実行されます(非推奨)
- 多くの場合、依存配列を指定して、必要な時だけ実行するようにします
依存配列の基本
依存配列を使うことで、useEffectを実行するタイミングを制御できます。
📊 依存配列の3つのパターン比較
依存配列なし
useEffect(() => { ... });📰 例: 新聞配達員が毎日来る → 非推奨(パフォーマンス低下)
空の配列 []
useEffect(() => { ... }, []);🏠 例: 引っ越し時の一回だけの掃除 → API初期データ取得に最適
依存配列あり [count]
useEffect(() => { ... }, [count]);🔔 例: ドアベルが鳴るたびに対応 → 状態に応じた処理に最適
| パターン | 実行タイミング | 使用例 |
|---|---|---|
なし | 毎回のレンダリング後 | 非推奨 |
[] | マウント時のみ(1回) | API初期データ取得、タイマー設定 |
[count] | 値が変わる時 | 検索フィルター、状態に応じた処理 |
コンポーネントのライフサイクルとuseEffect
🎭 身近な例えで理解しよう:劇場の例
🎬 マウント時 = 劇が始まる
カーテンが上がる(コンポーネント表示)→ 照明が点灯(useEffect実行)
🔄 更新時 = シーンが変わる
舞台セットが変わる → 前の道具を片付ける → 新しい準備
🎭 アンマウント時 = 劇が終わる
カーテンが下りる → 照明を消し、道具を片付ける
⏸️ 待機 = 通常状態
副作用処理が実行中で、次の状態変化を待っている
📝 空の依存配列 [](マウント時のみ実行)
useEffect(() => {
// コンポーネントが初めて表示された時だけ実行される
console.log("初めて表示されました!");
// 例:APIからデータを取得
fetch("/api/data")
.then(response => response.json())
.then(data => console.log(data));
}, []); // ← 空の配列 []💡 空の依存配列[]を指定すると、コンポーネントがマウントされた時(初めて表示された時)に1回だけ実行されます。
📝 依存配列に値を指定(値が変わった時だけ実行)
const [count, setCount] = useState(0);
useEffect(() => {
// countが変わった時だけ実行される
console.log("countが変わりました:", count);
// 例:countが変わるたびにAPIを呼び出す
fetch(`/api/data?count=${count}`)
.then(response => response.json())
.then(data => console.log(data));
}, [count]); // ← countを指定💡 依存配列にcountを指定すると、countの値が変わるたびに実行されます。
✅ 依存配列の使い分け
- 空の配列 []: コンポーネントが表示された時だけ実行(API初期データ取得など)
- 値の指定 [count]: 指定した値が変わった時だけ実行(フィルター、検索など)
- 複数の値 [count, name]: いずれかの値が変わった時に実行
クリーンアップ関数
useEffectは、クリーンアップ関数を返すことができます。 この関数は、useEffectが再実行される前や、コンポーネントが削除される時に実行されます。
🧹 クリーンアップ関数の動作フロー
useEffect実行
副作用処理を開始(タイマー設定、API呼び出しなど)
副作用処理実行中
const timer = setInterval(...)クリーンアップ関数を返す
return () => { clearInterval(timer); };⚡ トリガー: 状態変更 or アンマウント
⚠️ クリーンアップ実行
前回の処理をクリーンアップ
- clearInterval(timer)
- AbortController.abort()
- イベントリスナー削除
新しいuseEffect実行(オプション)
値が変更された場合のみ、新しい処理を実行
🧹 身近な例えで理解しよう
🏠 お部屋の例え
クリーンアップ関数は「引っ越す前に部屋を片付ける」ようなものです。新しい処理を始める前や、コンポーネントが削除される時に、前の処理の後始末をします。
⏰ アラーム時計の例え
アラームをセットする(useEffect実行)→ 新しいアラームをセットする前に、前のアラームをキャンセルする(クリーンアップ)。実行順序: 1. 前回のクリーンアップ実行 → 2. 新しいuseEffect実行(値が変更された場合のみ)
用途: タイマーのクリア、APIリクエストのキャンセル、イベントリスナーの削除など、リソースの適切な解放を行います。
📝 クリーンアップ関数の基本構文
useEffect(() => {
// 副作用処理
const timer = setInterval(() => {
console.log("1秒ごとに実行");
}, 1000);
// クリーンアップ関数を返す
return () => {
clearInterval(timer); // タイマーをクリア
};
}, []);💡 クリーンアップ関数は、副作用処理で作成したリソース(タイマー、イベントリスナーなど)を適切に解放するために使用します。
⚠️ クリーンアップが必要な理由
- メモリリークの防止: タイマーやイベントリスナーを削除しないと、メモリリークが発生する可能性があります
- リソースの適切な解放: 不要になったリソースを適切に解放することで、アプリケーションのパフォーマンスが向上します
- 予期しない動作の防止: コンポーネントが削除された後も処理が実行され続けることを防ぎます
useStateとuseEffectの連携
useStateとuseEffectは、一緒に使うことで非常に強力な組み合わせになります。
🔄 useStateとuseEffectの連携図解
useState
状態を管理
const [count, setCount] = useState(0);状態: count
初期値: 0
状態変更
setCount(5)
count: 0 → 5useEffect
自動実行
useEffect(() => { ... }, [count]);副作用処理実行
countの新しい値(5)を使用
• API呼び出し
• ページタイトル更新
• DOM操作
🔄 身近な例えで理解しよう:温度計とエアコンの例
🌡️ 1. 状態の定義 = 温度計を設置
useStateで状態(count)を定義。これは「温度計」のようなもので、現在の温度(値)を表示します。
🔥 2. 状態の変更 = 温度が上がる
setCount(5)でcountが0から5に変更。これは「温度が25度から30度に上がった」ようなものです。
👁️ 3. useEffectの監視 = 温度計を見ているセンサー
useEffectは依存配列にcountを含めているため、countが変わると自動的に再実行されます。
❄️ 4. 副作用の実行 = エアコンが自動で動く
useEffect内でcountの新しい値(5)を使って、API呼び出しやDOM操作などの副作用処理を実行します。
📝 基本的な連携パターン
const MyComponent = () => {
const [count, setCount] = useState(0);
// countが変わるたびに実行
useEffect(() => {
console.log("countが変わりました:", count);
// countの値を使って何か処理
document.title = `カウント: ${count}`;
}, [count]); // ← countを依存配列に含める
return (
<div>
<p>カウント: {count{}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
};💡 useStateで状態を管理し、useEffectでその状態に応じた副作用処理を実行する、これが最も一般的なパターンです。
⚠️ 重要な注意点
- 依存配列に必ず含める: useEffect内で使用している状態やpropsは、依存配列に必ず含める必要があります
- 古い値を参照する可能性: 依存配列に含めないと、古い値が参照される可能性があります
- ESLintの警告: React HooksのESLintルールが、依存配列の不足を警告してくれます
実践的な例
実際によく使われるuseEffectの使い方を見てみましょう。
📝 例1: ページタイトルを変更する
const MyComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
// ページタイトルを変更
document.title = `カウント: ${count}`;
}, [count]); // countが変わるたびに実行
return (
<div>
<p>カウント: {count{}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
};💡 ブラウザのタブに表示されるタイトルを、状態に応じて動的に変更できます。
📝 例2: タイマーを設定する
const Timer = () => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// タイマーを設定(1秒ごとに実行)
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// クリーンアップ関数(後で説明)
return () => {
clearInterval(interval);
};
}, []); // マウント時のみ実行
return <p>経過時間: {seconds{}秒</p>;
};💡 コンポーネントが表示されたときにタイマーを開始し、削除されたときにタイマーをクリアします。
📝 例3: APIからデータを取得する
🌐 API呼び出しの流れ図解
コンポーネントマウント
コンポーネントが画面に表示されると、useEffectが自動的に実行されます
useEffect(() => { ... }, []);ローディング状態
API呼び出し前に、ローディング状態をtrueに設定して、ユーザーに読み込み中であることを伝えます
setLoading(true);API呼び出し
fetchを使ってサーバーからデータを取得します
fetch("/api/user") .then(...)データ取得成功
取得したデータを状態に保存し、ローディング状態をfalseに戻します
setUser(data); setLoading(false);画面に表示
状態が更新されると、コンポーネントが自動的に再描画され、データが画面に表示されます
🍕 身近な例えで理解しよう:ピザ配達の例
📞 1. ピザを注文する
電話をかける(コンポーネント表示)→ ピザ屋に注文を入れる
⏳ 2. 「お待ちください」と伝える
「ただいまお作りしています」と伝える(ローディング状態)
🚗 3. ピザを作って配達する
ピザ屋でピザを作る(サーバー処理)→ 配達する(API呼び出し)
🍽️ 4. ピザを食べる
ピザを受け取る(データ取得)→ 食べる(画面に表示)
const UserProfile = () => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// ローディング状態をtrueに設定
setLoading(true);
// APIからデータを取得
fetch("/api/user")
.then(response => response.json())
.then(data => {
setUser(data);
setLoading(false);
})
.catch(error => {
console.error("エラー:", error);
setLoading(false);
});
}, []); // マウント時のみ実行
if (loading) return <p>読み込み中...</p>;
if (!user) return <p>ユーザーが見つかりません</p>;
return <div>こんにちは、{user.name{}さん</div>;
};💡 この例の流れ
- コンポーネントがマウントされると、useEffectが実行されます
- ローディング状態をtrueに設定して、ユーザーに読み込み中であることを伝えます
- fetch APIを使ってサーバーからデータを取得します
- データ取得成功時に、状態を更新してローディングをfalseにします
- 状態が更新されると、コンポーネントが再描画されて、データが画面に表示されます
まとめ
🎯 覚えておきたいポイント
useEffectは副作用処理を実行するためのフックですuseEffect(() => { ... }, [依存配列]);の形式で使用します- 依存配列が
[](空)の場合、マウント時のみ実行されます - 依存配列に値を指定すると、その値が変わった時だけ実行されます
- 依存配列を指定しない場合、毎回のレンダリング後に実行されます(非推奨)