useEffectはReactコンポーネントが表示された後に実行される関数を登録するための仕組みです。
import { useEffect } from "react";
function MyComponent() {
useEffect(() => {
console.log("この中の処理は、画面に表示された後に実行されるよ!");
}, []);
return <div>Hello</div>;
}
このコンポーネントの実行順:
MyComponent()
関数が呼ばれる- JSX (
<div>Hello</div>
) を返す
- JSX (
- ReactがこのJSXをDOMに描画する
<div>Hello</div>
がブラウザの画面に表示される!
- 表示が終わった“あとで”
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>;
}
- 最初
show
はtrue
なので<Message />
が表示される → マウント(表示) - ボタンを押して
show
がfalse
になると<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>
</>
);
}