【ITニュース解説】⚡React useEffect Hook — Side Effects Made Simple
2025年09月20日に「Dev.to」が公開したITニュース「⚡React useEffect Hook — Side Effects Made Simple」について初心者にもわかりやすく解説しています。
ITニュース概要
ReactのuseEffectは、関数コンポーネントでデータ取得やDOM更新といった「副作用」を扱うHookだ。レンダリング後に実行され、依存配列で実行タイミングを制御できる。不要な処理を止めるクリーンアップ機能もあり、メモリリークを防ぐ。UIと副作用を同期させるのに役立つ。
ITニュース解説
Reactを学ぶ上で、特にWebアプリケーション開発の世界でUI(ユーザーインターフェース)を構築する際に非常に重要な概念の一つに、「Reactのフック」がある。その中でも、「useEffectフック」は、アプリケーションが外部と連携する「副作用」と呼ばれる処理を、安全かつ効率的に管理するために欠かせない機能だ。システムエンジニアを目指す初心者にとって、このuseEffectフックの理解は、モダンなReact開発の扉を開く鍵となるだろう。
まず、Reactの基本的な仕組みから軽く触れておこう。Reactは、コンポーネントという小さな部品を組み合わせてUIを構築していくライブラリだ。これらのコンポーネントは、ユーザーの操作やデータの変化に応じて画面を再描画(レンダー)し、常に最新の状態を保つ。以前は「クラスコンポーネント」という形式が主流だったが、近年ではよりシンプルで直感的に書ける「関数コンポーネント」が広く使われている。しかし、関数コンポーネントだけでは、コンポーネントの状態(ステート)を管理したり、ライフサイクルイベント(コンポーネントが表示された時、更新された時、消えた時など)に応じた処理を行うのが難しかった。そこで登場したのが「フック」という機能で、useStateや今回解説するuseEffectなどがある。これらフックを使うことで、関数コンポーネントでもステート管理やライフサイクルに応じた処理が簡単に行えるようになった。
では、今回の主役であるuseEffectフックが何をするものか。「副作用(Side Effects)」という言葉がポイントになる。プログラミングにおいて、関数は通常、与えられた入力に対して常に同じ出力を返し、外部の何かを変更しない「純粋な関数」であることが理想とされる。しかし、現実のアプリケーション開発では、外部とのやり取りが不可欠だ。例えば、Webサーバーからデータを取得する、Webページのタイトルを更新する、タイマーを設定する、イベントリスナーを登録するといった処理は、すべて「副作用」に該当する。これらは、関数の実行が外部の状態に影響を与えたり、外部の状態に依存したりする処理のことだ。Reactアプリケーションでは、UIの表示(レンダー)自体は純粋な処理を目指すが、データ取得やDOM操作といった外部との連携は必ず発生する。これらの副作用を、コンポーネントのライフサイクルに合わせて適切に実行・管理するのがuseEffectの役割なのだ。
useEffectフックは、次のように記述する。第一引数には実行したい副作用の処理を記述した関数(エフェクト関数)を、第二引数には依存する値の配列を指定する。この依存配列が、エフェクト関数を「いつ」再実行するかを決定する非常に重要な要素だ。
例を見てみよう。ユーザーがボタンをクリックするたびに、ページタイトルを更新するアプリケーションがある。
1import { useEffect, useState } from "react"; 2 3function App() { 4 const [count, setCount] = useState(0); // countという状態を管理 5 6 // countが変更されるたびに実行される副作用 7 useEffect(() => { 8 document.title = `Clicked ${count} times`; // ドキュメントのタイトルを更新 9 }, [count]); // countが依存配列 10 11 return ( 12 <button onClick={() => setCount(count + 1)}> 13 Click {count} 14 </button> 15 ); 16}
このコードでは、useState(0)を使ってcountという状態変数を定義し、ボタンがクリックされるたびにsetCount関数でcountの値を増やしている。ここで注目すべきはuseEffectだ。useEffectの第一引数に渡された関数では、document.title(Webページのタイトル)を現在のcountの値に応じて更新している。これはまさに「副作用」の一つであるDOM操作だ。
そして、第二引数の依存配列[count]が、このエフェクトの実行タイミングを制御している。この配列にcountが指定されているため、countの値が前回のレンダー時と比べて変化した場合にのみ、useEffect内の処理が再実行される。つまり、ボタンがクリックされてcountが更新されるたびに、ページタイトルが新しいcountの値に合わせて更新されるというわけだ。useEffect内の処理は、コンポーネントが画面に表示された後、または再描画された後に実行されるため、「レンダー後に実行される」という特性を持つ。もし依存配列が空の[]だった場合、このエフェクトはコンポーネントが最初に画面に表示された時(初回レンダー時)に一度だけ実行され、それ以降はcountが変化しても再実行されない。依存配列を省略すると、コンポーネントが再レンダーされるたびにエフェクトが実行されるため、意図しない挙動やパフォーマンスの問題を引き起こす可能性がある。そのため、基本的には常に適切な依存配列を指定することが推奨される。
useEffectのもう一つの重要な機能は「クリーンアップ」だ。アプリケーションのパフォーマンス維持やメモリリークの防止のために、不要になった副作用の後処理を行う必要がある場合がある。例えば、タイマーの設定やイベントリスナーの登録など、コンポーネントが画面から消えたり、エフェクトが再実行されたりする前に、以前の処理を停止したり解除したりする必要がある場合にクリーンアップが活躍する。
クリーンアップは、useEffectの第一引数に渡すエフェクト関数が「関数を返す」ことで実現される。この返された関数が、クリーンアップ関数として機能し、次回のエフェクト実行前やコンポーネントがアンマウントされる(画面から消える)直前に呼び出される。
例を見てみよう。定期的にコンソールにメッセージを表示するタイマーを設定するケースだ。
1useEffect(() => { 2 const timer = setInterval(() => console.log("Running..."), 1000); // 1秒ごとに実行されるタイマー 3 return () => clearInterval(timer); // クリーンアップ関数 4}, []); // 依存配列が空なので、初回レンダー時とアンマウント時にのみ実行
このコードでは、setInterval関数を使って1秒ごとに「Running...」とコンソールに表示するタイマーを設定している。このsetIntervalは、明示的に停止しない限り動き続けてしまう。そこで、useEffectのエフェクト関数が() => clearInterval(timer)という関数を返している。この返された関数がクリーンアップ関数となり、コンポーネントが画面から消える時や、このuseEffectが再度実行される時(この例では依存配列が空なので、再実行されることはない)に呼び出され、clearInterval(timer)によってタイマーを停止する。これにより、コンポーネントが不要になった後もタイマーが動き続けてメモリを消費したり、意図しない処理が実行されたりするのを防ぐことができる。
まとめると、useEffectフックは、関数コンポーネントにおいて「副作用」と呼ばれる外部とのやり取りを、コンポーネントのライフサイクルに合わせて適切に管理するための強力なツールだ。レンダー後に副作用を実行し、依存配列によって実行タイミングを制御し、必要に応じてクリーンアップ関数を返すことで、メモリリークを防ぎ、アプリケーションの安定性を高める。最初は少し複雑に感じるかもしれないが、Reactアプリケーションでデータの取得、DOMの直接操作、タイマーの設定などを行う際には、このuseEffectが不可欠となる。UI(ユーザーインターフェース)の表示と、その裏で行われる外部との連携を同期させることで、堅牢で効率的なWebアプリケーションを構築するための基盤となる機能だ。システムエンジニアを目指す上では、このuseEffectフックを深く理解し、適切に使いこなせるようになることが、React開発者としての大きな一歩となるだろう。