この課題のねらい
ここからが「実用的な React」に一気に近づくところです。
テーマは useEffect──「画面に表示する以外の処理(=副作用)」を、いつ・どのタイミングで実行するかをコントロールするフックです。
初回表示時だけログを出す
state が変わったときだけ処理を走らせる
依存配列([] の部分)が何を意味しているかを言葉で説明できる
この3つを押さえれば、API 通信・タイマー・イベント登録など、実務でよくある処理の“入口”に立てます。
useEffectの基本イメージ
「副作用」をどこで書くか
useEffect は、ざっくり言うとこういうときに使います。
- 画面に表示する JSX とは別の処理をしたいとき
例:API からデータを取る、console.logでログを出す、setIntervalでタイマーを動かす、スクロールイベントを登録するなど。 - そしてそれを「いつ実行するか」を、依存配列でコントロールしたいとき。
形はこうです。
useEffect(() => {
// ここに「副作用」の処理を書く
}, [依存する値]);
TypeScript第一引数:実行したい処理(関数)
第二引数:その処理を「いつ実行するか」を決めるための配列(依存配列)。
この「依存配列」が、今回の挑戦課題の主役です。
必須課題① 初回表示時にconsole.log
「マウント時に一度だけ」実行するuseEffect
まずは一番シンプルなパターンから。
「コンポーネントが画面に初めて表示されたときに一度だけ console.log を出す」例です。
"use client";
import { useEffect } from "react";
export default function EffectExample() {
useEffect(() => {
console.log("コンポーネントが初回表示されました");
}, []); // ← ここがポイント
return (
<main style={{ padding: "24px", fontFamily: "sans-serif" }}>
<h1>useEffect 初回表示の例</h1>
<p>コンソールを開いてログを確認してみてください。</p>
</main>
);
}
TSXここでの重要ポイントは「依存配列が空の []」というところです。
[]を渡すと、「初回レンダリング時に一度だけ実行」になります。- つまり、「マウント時だけ実行したい処理」(初回データ取得、初期設定など)を書く場所として使えます。
ブラウザの DevTools を開いて Console タブを見ると、
ページを開いたタイミングで一度だけログが出ているはずです。
必須課題② state変更時に処理実行
「特定のstateが変わったときだけ」動くuseEffect
次は、「state が変わったときにだけ処理を走らせる」パターンです。
カウンターを例にしてみます。
"use client";
import { useEffect, useState } from "react";
export default function CounterWithEffect() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("count が変わりました:", count);
}, [count]); // ← count を依存配列に入れる
function handleIncrement() {
setCount((prev) => prev + 1);
}
return (
<main style={{ padding: "24px", fontFamily: "sans-serif" }}>
<h1>useEffect と state の連動</h1>
<p>現在のカウント: {count}</p>
<button onClick={handleIncrement}>+1</button>
<p style={{ marginTop: "8px" }}>
ボタンを押すたびに、コンソールにログが出ます。
</p>
</main>
);
}
TSXここでの流れを言葉で追ってみます。
- 画面が初めて表示される(
count = 0)
→useEffectが一度実行され、「count が変わりました: 0」とログが出る。 - ボタンを押して
setCountが呼ばれる
→countが 1 に変わる
→ 再レンダリング後、[count]の依存配列を見て「count が変わった」と判断
→useEffectが再実行され、「count が変わりました: 1」とログが出る。 - 以降、
countが変わるたびに同じ流れ。
ここで大事なのは、
- 「依存配列に書いた値が変わったときだけ」useEffect が再実行されるというルールです。
[count]と書いたので、「count が変わったときだけ」この effect が動きます。
もし依存配列を省略すると、すべてのレンダリング後に毎回実行されます。
ログを出すだけならまだしも、API 通信などを毎回やると大変なことになるので、
「いつ実行したいか」を意識して依存配列を書くのが超重要です。
挑戦課題 useEffectの依存配列を説明
依存配列とは何か
依存配列(Dependency Array)は、
「この useEffect は、どの値に“依存”しているかを React に教えるためのリスト」です。
React はこの配列を見て、
- その中のどれかが前回から変わった → effect を再実行
- 何も変わっていない → effect はスキップ
という判断をします。
よく言われる「黄金ルール」は、
useEffect の中で使っている外側の変数・state・props は、依存配列に入れる。
というものです。
3つの代表的なパターン
依存配列の書き方には、代表的に 3 パターンあります。
依存配列なし(省略)
useEffect(() => {
console.log("毎回実行される");
});
TypeScript- すべてのレンダリング後に毎回実行される。
- ログやデバッグならまだしも、重い処理を書くとパフォーマンスに悪影響が出やすいです。
空配列 []
useEffect(() => {
console.log("初回だけ実行される");
}, []);
TypeScript- 初回レンダリング時に一度だけ実行される。
- 初期データ取得・一度だけの設定処理などに使う。
特定の値を入れる [count, userId, ...]
useEffect(() => {
console.log("count が変わったときだけ実行される");
}, [count]);
TypeScriptcountが変わったときだけ effect が再実行される。- 「この処理はこの値に紐づいている」と明示するイメージです。
なぜ依存配列がそんなに大事なのか
依存配列を正しく書かないと、次のような問題が起きます。
- 必要以上に何度も effect が走ってしまい、パフォーマンスが悪くなる。
- 逆に、本当は再実行してほしいのに依存配列に入れ忘れて、古い値のまま処理してしまう(いわゆる「stale state」)。
setStateを使った処理と組み合わせると、依存配列のミスで無限ループになることもある。
だからこそ、React の公式や lint は、
useEffect の中で使っている外側の値は、基本的に全部依存配列に入れよう。
と強く言っています。
警告が出たら「うるさいな」ではなく、「なぜそれを入れろと言っているのか?」を考えるクセをつけると、一気にレベルが上がります。
まとめ:useEffectでつかんでほしいこと
この課題で本当に押さえてほしいのは、次の感覚です。
useEffectは「画面表示とは別の処理(副作用)」を書く場所。- 依存配列で「いつ実行するか」をコントロールする。
[]→ 初回だけ[count]→ count が変わったときだけ- 省略 → 毎回
- 「useEffect の中で使っている外側の値は、依存配列に入れる」が基本ルール。
ここが腑に落ちると、
- 初回表示時に API からデータを取る
- 特定の state が変わったときだけローカルストレージに保存する
- ウィンドウサイズの変化に応じてレイアウトを変える
といった“実用的な React の動き”を、自分の頭で設計できるようになっていきます。

