🚀【React超入門】useEffectの基本パターンと実務で使える応用テクニック大全
✅ はじめに:useEffectって結局なんなの?
Reactの開発で「動きはするけど、なんか気持ち悪い」コードになった経験、ありませんか?
その多くは、副作用(side effects)を適切に扱えていないことが原因です。
たとえば以下のような状況:
- コンポーネントが更新されるたびに無駄なAPIリクエストが発生する
- タイマーが複数重複して動作している
- アンマウント後にもsetStateが走って警告が出る
これらの問題を防ぐ鍵が、Reactのフック useEffect
です。
本記事では、次の3ステップでuseEffect
を深く理解していきます。
🌟 目次
- なぜuseEffectが必要なのか?(背景と問題提起)
- useEffectの基本構文と典型パターン3選
- 実践例:API取得とイベントリスナー管理
- よくあるエラーとトラブル対処法
- 応用:カスタムHook・状態管理との連携
- 実務Tips:チーム開発におけるuseEffectの設計戦略
- まとめと今後の展望
🧭 1. なぜuseEffectが必要なのか?
Reactは宣言的なUIライブラリです。基本的にはprops
やstate
をもとに「UIの見た目」を制御します。しかし実際の開発では、次のようなUI以外の処理=副作用が頻繁に発生します。
処理例 | 内容 |
---|---|
API通信 | データを取得して表示したい |
DOMアクセス | スクロールやfocusの操作 |
外部ライブラリ | Google MapsやChart.jsなど |
イベント管理 | resizeやscrollイベント |
このような副作用を安全・確実に扱うために登場したのが、React Hooksのひとつである**useEffect
**です。
🧪 2. useEffectの基本構文とパターン3選
🔤 基本構文(語句の意味も解説)
useEffect(() => {
// 実行したい処理
return () => {
// クリーンアップ処理(任意)
};
}, [依存配列]);
部分 | 解説 |
---|---|
第一引数(コールバック関数) | 実行したい副作用の処理(API呼び出し、イベント登録など) |
return内 | 副作用のクリーンアップ処理(タイマー停止など) |
依存配列 | どの値の変更を監視するかを指定する |
📘 パターン①:初回マウント時のみ(componentDidMount相当)
useEffect(() => {
console.log("初回のみ実行");
}, []);
✅ 主な用途:
- 初回のデータ取得(例:ユーザー情報)
- 初期化処理(例:外部SDKの設定)
📘 パターン②:特定state/propsの変更時に実行
useEffect(() => {
console.log("countが変更されました");
}, [count]);
✅ 主な用途:
- 値の変更に伴う再取得
- input値に応じたバリデーション
- アニメーションの切り替え処理
📘 パターン③:クリーンアップ付き処理(componentWillUnmount相当)
useEffect(() => {
const id = setInterval(() => {
console.log("動いてる...");
}, 1000);
return () => {
clearInterval(id);
console.log("停止しました");
};
}, []);
✅ 主な用途:
- イベントやタイマーのクリーンアップ
- WebSocket、Observerの解除
- アンマウント時の状態リセット
🛠️ 3. 実践①:API取得とイベント管理の完全例
🔍 ユーザー一覧取得(実務でよく使う)
const UserList = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
const data = await res.json();
setUsers(data);
} catch (err) {
console.error("取得失敗:", err);
}
};
fetchData();
}, []);
🧠 解説ポイント:
-
useEffect
内で非同期処理は関数を定義して中で呼び出す - try-catchでエラーハンドリングも忘れずに
🔍 スクロール位置に応じてボタン表示
useEffect(() => {
const handleScroll = () => {
if (window.scrollY > 100) {
setShowButton(true);
} else {
setShowButton(false);
}
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
🧨 4. よくあるエラーと対処法
❌ 非同期関数を直接useEffectに書く
useEffect(async () => {
const res = await fetch(...);
}, []); // ⛔ エラーになる
✅ 正しくは:
useEffect(() => {
const fetchData = async () => { ... };
fetchData();
}, []);
❌ 無限レンダリング
useEffect(() => {
setCount(count + 1);
}, [count]); // ⛔ countが変わる→再実行→countが変わる→再実行...
✅ 対策:状態更新を分ける、または条件分岐
⚠️ メモリリークの警告
Warning: Can't perform a React state update on an unmounted component.
✅ クリーンアップ処理で防止、またはフラグを使う:
useEffect(() => {
let isMounted = true;
fetch(...).then(data => {
if (isMounted) setData(data);
});
return () => { isMounted = false };
}, []);
🔄 5. 応用:カスタムHook + 状態管理との連携
🎯 カスタムHookで共通ロジックを抽出
const useDocumentTitle = (title) => {
useEffect(() => {
document.title = title;
}, [title]);
};
// 使用例
useDocumentTitle("マイページ");
🎯 ZustandやRecoilとの組み合わせ
状態がグローバルに管理されている場合でも、監視対象を限定することで無駄な再レンダリングを抑えることができます。
const user = useUserStore(state => state.user);
useEffect(() => {
console.log("userが変化したら実行");
}, [user]);
👥 6. 実務Tips:チーム開発での設計ノウハウ
✅ useEffectの「役割」を分離する
1つのuseEffect
にあれもこれも詰め込まない。用途ごとに分割することで、可読性と保守性がアップ。
useEffect(() => { /* 初期取得 */ }, []);
useEffect(() => { /* イベント登録 */ }, []);
useEffect(() => { /* フォーカス制御 */ }, [isActive]);
✅ 依存配列のコメントは書くと親切
useEffect(() => {
...
}, [userId]); // userIdが変わるたびに再取得される
✅ eslint-plugin-react-hooksを導入
依存配列の漏れを静的解析で防げる。プロジェクト初期から設定しておくと事故が減る。
npm install eslint-plugin-react-hooks --save-dev
📌 7. まとめ
項目 | ポイント |
---|---|
基本 | useEffectは副作用を安全に制御するためのフック |
パターン | 初回のみ・値変化時・クリーンアップ付きの3つをマスター |
実践 | API取得、イベント登録、スクロール管理などに活用 |
注意点 | 無限ループ・非同期処理・メモリリークに要注意 |
応用 | カスタムHookや状態管理と組み合わせると真価を発揮 |
🧭 今後の展望:useEffectの限界と次の一手
React 19以降、useEventやReact Server Componentsといった新機能により、副作用やイベント管理のあり方も進化しています。将来的にはuseEffect
の使用頻度も変化していく可能性がありますが、今なお最も基本的かつ重要なフックであることは変わりません。
✨おわりに
この記事が、あなたのuseEffect理解の助けになれば嬉しいです。
「ReactはJSX書くだけ」と思っていた方も、useEffectを正しく使うことで、より堅牢で直感的なコンポーネント設計が可能になります。
次回は、**「APIを呼び出して表示する」
気になる方はぜひフォロー&スキをお願いします 🙌
ご希望があれば、このシリーズをPDF化やQiita投稿用のMarkdown形式にも変換可能です!お気軽にお申し付けください。