ReactでuseEffectを複数使う場合のベストプラクティス!初心者でもわかるReactフック活用法
生徒
「先生、ReactでuseEffectを複数使いたいんですが、どのように書けば良いですか?」
先生
「useEffectは複数使っても大丈夫ですが、使い方にはコツがあります。」
生徒
「コツとは何ですか?」
先生
「目的ごとに分けて書くことです。例えば、データ取得用、状態更新用、イベント監視用と分けると管理がしやすくなります。」
生徒
「それぞれ別にuseEffectを書いたほうが良いんですね?」
先生
「そうです。依存関係も個別に管理できるので、意図しない再レンダリングを避けやすくなります。」
1. useEffectを複数使う基本ルール
Reactでは、1つのコンポーネントの中でuseEffectを複数使うことができます。 初心者の方がまず意識したい基本ルールは、「1つのuseEffectには1つの役割だけを持たせる」という考え方です。 すべての処理をまとめて書いてしまうと、何が原因で処理が動いたのか分かりにくくなってしまいます。
処理の目的ごとにuseEffectを分けておくと、状態と処理の関係がはっきりし、 どの値が変わったときに何が実行されるのかを自然に理解できるようになります。 これはReactの仕組みに慣れるうえで、とても大切なポイントです。
import React, { useState, useEffect } from "react";
function App() {
const [count, setCount] = useState(0);
const [title, setTitle] = useState("こんにちは");
// カウント更新用
useEffect(() => {
console.log("カウントが更新されました:", count);
}, [count]);
// タイトル更新用
useEffect(() => {
document.title = title;
}, [title]);
return (
{title}
);
}
export default App;
2. 複数useEffectの利点
複数のuseEffectを使う最大の利点は、「処理の役割がはっきりする」ことです。 1つのuseEffectにすべての処理をまとめてしまうと、どの状態変更がきっかけで動いているのか分かりにくくなります。 反対に、目的ごとにuseEffectを分けておくと、コードを読んだときに流れを直感的に理解できます。
たとえば、画面表示の更新とログ出力を別々のuseEffectにすると、 「表示に関する処理」と「内部の動作確認」が混ざらず、安心して修正できます。 これはReact初心者の方がつまずきやすいポイントを避けるうえでも、とても効果的です。
import React, { useState, useEffect } from "react";
function App() {
const [message, setMessage] = useState("こんにちは");
// 表示更新用
useEffect(() => {
document.title = message;
}, [message]);
// ログ出力用
useEffect(() => {
console.log("メッセージが変更されました");
}, [message]);
return (
<div>
<p>{message}</p>
<button onClick={() => setMessage("ボタンがクリックされました!")}>
変更
</button>
</div>
);
}
export default App;
3. 依存関係(dependency)の管理が重要
useEffectでは、第2引数に「依存関係の配列」を指定します。 この配列は、「どの値が変わったときに、このuseEffectを実行するか」をReactに伝えるためのものです。 複数useEffectを使う場合は、それぞれの役割に合った依存関係を正しく設定することがとても重要になります。
依存関係を意識せずに書いてしまうと、関係のない状態変更でもuseEffectが動いてしまい、 「なぜこのタイミングで処理が実行されたのか分からない」という状態になりがちです。 初心者の方は、「この処理は、どの値が変わったときに必要なのか」を一つずつ確認しながら設定するのがおすすめです。
import React, { useState, useEffect } from "react";
function App() {
const [title, setTitle] = useState("こんにちは");
const [count, setCount] = useState(0);
// タイトル変更時だけ実行されるuseEffect
useEffect(() => {
console.log("タイトルが変更されました:", title);
}, [title]); // titleの変化だけを監視
return (
<div>
<h1>{title}</h1>
<button onClick={() => setTitle("タイトルが変わりました")}>
タイトル変更
</button>
<button onClick={() => setCount(count + 1)}>
カウントを増やす
</button>
</div>
);
}
export default App;
4. 実践例:データ取得とカウント管理を分ける
function App() {
const [count, setCount] = useState(0);
const [data, setData] = useState(null);
// データ取得用useEffect
useEffect(() => {
const fetchData = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const result = await response.json();
setData(result);
};
fetchData();
}, []); // 初回マウント時のみ実行
// カウント更新用useEffect
useEffect(() => {
console.log("カウントが更新されました:", count);
}, [count]);
return (
データ: {data ? data.title : "読み込み中..."}
);
}
5. 複数useEffectを使うときのポイント
- 処理ごとにuseEffectを分けて、1つのuseEffectに多くの処理を詰め込まない
- 依存関係の配列を正確に指定して意図しない再レンダリングを防ぐ
- 非同期処理がある場合は内部でasync関数を定義して呼び出す
- コンポーネントのアンマウント時にはクリーンアップ関数を使う
6. useEffectを分けることで起きる読みやすさの違い
useEffectを1つにまとめて書いてしまうと、「どの処理が、どのタイミングで動いているのか」が分かりにくくなりがちです。 特にReact初心者の方は、状態が増えてきたときに処理の流れを追うのが大変になります。 useEffectを目的ごとに分けておくことで、コードを見た瞬間に「これは何の処理か」が理解しやすくなります。
たとえば「データ取得」「画面タイトル変更」「ログ出力」といった役割が明確であれば、 後から見返したときや修正するときも迷いにくくなります。 結果として、Reactコンポーネント全体の可読性が大きく向上します。
7. useEffectを分けたほうがバグを防ぎやすい理由
useEffectを複数に分ける最大のメリットの一つが、バグを見つけやすくなることです。 1つのuseEffectに多くの処理が入っていると、依存関係の指定ミスに気づきにくく、 意図しない再実行や無限ループの原因になります。
処理ごとにuseEffectを分けておけば、「この状態が変わったときに、この処理だけが動く」 という関係がはっきりします。 そのため、動作確認やデバッグもしやすくなり、安心してコードを書き進められます。
8. 複数useEffectを使いこなすための考え方
複数useEffectを使うときは、「何をきっかけに動く処理なのか」を意識することが大切です。 状態の変化、初回表示、外部データの取得など、実行タイミングごとにuseEffectを分けることで、 Reactの挙動が自然に理解できるようになります。
最初は「useEffectは1つで十分では?」と感じるかもしれませんが、 実際の開発では状態や処理が増えていくのが普通です。 早い段階から複数useEffectに慣れておくことで、より実践的なReactの書き方が身につきます。
まとめ
複数のuseEffectを使う意味を振り返る
今回の記事では、ReactでuseEffectを複数使う場合の考え方や書き方について、基礎から実践まで丁寧に確認してきました。 useEffectはReactフックの中でも特に重要な存在で、画面表示後の処理や状態変化に応じた処理を柔軟に書ける反面、 使い方を誤ると処理の流れが分かりにくくなったり、意図しない再レンダリングが発生したりします。 そこで大切になるのが、「useEffectを目的ごとに分けて使う」という考え方です。
ひとつのuseEffectに複数の役割を持たせてしまうと、どの状態変更がきっかけで処理が実行されたのかが分かりづらくなります。 一方で、データ取得用、画面更新用、ログ出力用など、役割ごとにuseEffectを分けておくと、 それぞれの処理がどのタイミングで動くのかがはっきりし、コード全体の見通しが良くなります。 これはReact初心者が「なぜこの処理が動いたのか分からない」と悩む場面を減らすためにも非常に有効です。
依存配列を正しく設定する重要性
複数useEffectを使ううえで欠かせないのが、依存配列の正しい管理です。 依存配列は「どの値が変わったときに、このuseEffectを実行するか」をReactに伝える役割を持っています。 この指定が曖昧だと、関係のない状態変更でも処理が走ってしまい、バグや無駄な再実行の原因になります。 逆に、依存関係を正確に指定できていれば、Reactの動作はとても素直で理解しやすくなります。
useEffect(() => {
console.log("タイトルが変更されました");
}, [title]);
useEffect(() => {
console.log("カウントが更新されました");
}, [count]);
このように処理と依存関係を対応させて書くことで、 「どの値が変わると、どの処理が動くのか」をコードから自然に読み取れるようになります。 複数useEffectは難しそうに見えて、実はReactの仕組みを理解するための近道でもあります。
読みやすさと保守性が大きく向上する
useEffectを分けることは、単に動作を安定させるだけでなく、コードの読みやすさや保守性を高める効果もあります。 後からコードを見返したときに、「このuseEffectは何のための処理か」がすぐに分かる状態は、 実務やチーム開発において非常に大きなメリットになります。 修正や追加を行う際も、影響範囲を把握しやすく、不要なバグを生みにくくなります。
React開発では、最初は小さなコンポーネントでも、少しずつ状態や処理が増えていくのが一般的です。 そのときに、早い段階から複数useEffectを使い分ける習慣が身についていれば、 規模が大きくなっても混乱せずに対応できるようになります。 今回学んだ考え方は、今後のReact開発でも長く役立つはずです。
生徒
「useEffectは一つにまとめたほうがシンプルだと思っていましたが、役割ごとに分けたほうが分かりやすい理由がよく分かりました。」
先生
「そうですね。useEffectは増えても問題ありません。むしろ分けることで、Reactの状態管理や処理の流れが整理されます。」
生徒
「依存配列を意識するだけで、なぜ処理が動くのか理解しやすくなりました。デバッグもしやすそうです。」
先生
「その感覚はとても大切です。複数useEffectを正しく使えるようになると、Reactのコードが一気に読みやすくなりますよ。」