ReactのcomponentDidMountとuseEffectの違いを徹底解説!初心者でもわかるReactライフサイクルの基本
生徒
「先生、ReactのcomponentDidMountとuseEffectってよく聞くんですけど、何が違うんですか?」
先生
「とても大事な質問ですね。どちらも“コンポーネントが画面に表示されたときに実行される処理”に関係しますが、書き方や使い方が少し違うんです。」
生徒
「なるほど…。でも、どっちを使えばいいんですか?」
先生
「最近のReactでは関数コンポーネントでuseEffectを使うのが一般的です。ただ、昔のコードにはcomponentDidMountがよく使われているので、両方理解しておくことが大事ですよ。」
生徒
「わかりました!では、実際にどんな風に使うのか見てみたいです!」
1. Reactのライフサイクルとは?
まず「ライフサイクル」という言葉を聞くと難しそうですが、簡単に言うと「コンポーネント(Reactの部品)が生まれてから消えるまでの流れ」のことです。
たとえば、あなたがWebページを開いた瞬間にコンポーネントが「作られる」そして、何かボタンを押したりして状態が変わると「更新される」。最後にページを閉じると「消える」。これがReactのライフサイクルの流れです。
クラスコンポーネントでは、この流れにあわせて特別な関数(メソッド)を使って処理を行います。その代表がcomponentDidMountです。
2. componentDidMountとは?
componentDidMountは、クラスコンポーネントで使うライフサイクルメソッドの1つです。「コンポーネントが最初に画面に表示されたあと(マウントされたあと)」に一度だけ呼び出されます。
つまり、「初回表示後に何か処理をしたい」ときに使います。たとえば、WebAPIからデータを取得したり、外部サービスと通信するような処理です。
import React from "react";
class App extends React.Component {
componentDidMount() {
console.log("コンポーネントが画面に表示されました!");
}
render() {
return <h1>こんにちは!Reactクラスコンポーネントです。</h1>;
}
}
export default App;
このようにcomponentDidMountは一度だけ実行されるので、初期化処理などによく使われます。
3. useEffectとは?
次に、関数コンポーネントで使うのがuseEffectです。これはReactの「フック(Hook)」という機能のひとつで、クラスコンポーネントで行っていたライフサイクルの処理を関数でも書けるようにしたものです。
useEffectは、コンポーネントが表示されたとき(マウント時)や、更新されたときに実行される関数を設定できます。
import React, { useEffect } from "react";
function App() {
useEffect(() => {
console.log("コンポーネントが画面に表示されました!");
}, []);
return <h1>こんにちは!React関数コンポーネントです。</h1>;
}
export default App;
[](空の配列)を第2引数に渡すことで、「最初の1回だけ」実行されるようになります。これはcomponentDidMountと同じタイミングです。
4. componentDidMountとuseEffectの違い
どちらも似ていますが、使い方と仕組みに違いがあります。ここで整理してみましょう。
| 比較項目 | componentDidMount | useEffect |
|---|---|---|
| 使う場所 | クラスコンポーネント | 関数コンポーネント |
| 実行タイミング | 初回レンダリング後に1回だけ | 第2引数(依存配列)により制御 |
| 書き方 | メソッドとして定義 | 関数内で呼び出し |
| アンマウント処理 | componentWillUnmountを使用 |
useEffectの中でクリーンアップ関数を返す |
React公式ドキュメントでも、今後はクラスコンポーネントよりも「関数コンポーネント+フック」を使う方法が推奨されています。
5. useEffectでアンマウント処理(片付け処理)をする例
コンポーネントが画面から消えるときに処理を行いたい場合、useEffectの中で「クリーンアップ関数」を返します。
import React, { useEffect } from "react";
function App() {
useEffect(() => {
console.log("マウントされました");
return () => {
console.log("アンマウントされました");
};
}, []);
return <h1>useEffectのクリーンアップの例</h1>;
}
export default App;
このように、useEffectでは「表示されたときの処理」と「消えるときの処理」を一緒に書けるので、とても便利です。
6. どちらを使うべき?
今のReact開発では、基本的にuseEffectを使うのが主流です。理由は、コードがシンプルになり、状態管理や再利用がしやすくなるからです。
ただし、古いReactプロジェクト(React 16以前など)ではクラスコンポーネントが使われていることも多いので、componentDidMountの仕組みも知っておくと安心です。
Reactを学ぶうえでは、両方の理解ができるとより深くReactのライフサイクルを理解できます。
まとめ
ここまでReactのライフサイクルにおける重要な要素であるcomponentDidMountとuseEffectについて詳しく解説してきました。Reactの進化とともに、コンポーネントの管理方法はクラスベースから関数ベースへと大きくシフトしています。しかし、どちらの知識も現場では欠かせません。
Reactライフサイクルの核心:なぜ使い分けるのか
Reactのコンポーネント開発において、最も頻繁に行われるのが「データの取得(APIコール)」や「DOMの直接操作」、「イベントリスナーの設定」といった副作用(Side Effects)の処理です。これらの処理を適切なタイミングで実行しないと、無限ループに陥ったり、メモリリークが発生してアプリケーションの動作が重くなったりする原因になります。
componentDidMountは、まさに「画面に絵が出た直後のタイミング」を狙い撃ちするためのメソッドでした。一方で、モダンなReact開発で主流となっているuseEffectは、マウント時だけでなく「特定のデータが変わったとき」や「画面から消えるとき」の処理をひとまとめに記述できる柔軟性を持っています。
実戦で役立つ!useEffectの応用コードサンプル
ここでは、実際のフロントエンド開発でよく遭遇する「ウィンドウサイズを監視する処理」を例に、Next.jsやReactで使える具体的なコードを見てみましょう。このコードでは、マウント時にイベントを登録し、アンマウント時に適切に解除する「クリーンアップ」の流れを網羅しています。
import React, { useState, useEffect } from "react";
function WindowSizeLogger() {
const [width, setWidth] = useState(0);
useEffect(() => {
// 画面が表示されたときに実行される(componentDidMount相当)
const handleResize = () => {
setWidth(window.innerWidth);
console.log("現在の横幅:", window.innerWidth);
};
// 初期値をセット
setWidth(window.innerWidth);
// イベントリスナーの登録
window.addEventListener("resize", handleResize);
// クリーンアップ関数(componentWillUnmount相当)
return () => {
window.removeEventListener("resize", handleResize);
console.log("イベントリスナーを解除しました");
};
}, []); // 空の配列を渡すことで、初回のみ実行
return (
<div className="p-4 border rounded bg-light">
<h3>ウィンドウの横幅を計測中</h3>
<p>現在のブラウザの横幅は <strong>{width}px</strong> です。</p>
<p className="text-muted">※画面をリサイズしてコンソールを確認してください。</p>
</div>
);
}
export default WindowSizeLogger;
学習のポイント:依存配列(Dependency Array)の重要性
useEffectを使いこなす鍵は、第2引数に渡す配列にあります。この配列に変数を入れることで、その変数が変化したときだけ処理を再実行させることができます。
- 第2引数なし: レンダリングのたびに毎回実行(あまり使いません)
- 空の配列
[]: 初回のマウント時のみ実行(componentDidMountと同じ) - 変数あり
[data]: dataの値が変わったときだけ実行
このように、React Hookを使うことで、コンポーネントの状態管理が非常に直感的になります。Next.jsなどのフレームワークを使用する場合も、この基本原則は全く同じです。モダンなWeb開発を目指すなら、まずはuseEffectの挙動をマスターし、既存のクラスコンポーネントに出会った際にも慌てないようcomponentDidMountの概念を頭の片隅に置いておくのがベストな学習戦略と言えるでしょう。
生徒
「先生、ありがとうございました!componentDidMountとuseEffectの違い、だいぶ整理できてきました。要は、今の主流はuseEffectだけど、古いコードを読むためにはクラスコンポーネントの知識も必要ってことですね。」
先生
「その通りです。特にuseEffectの最後に書くreturn () => { ... }というクリーンアップの書き方は、メモリリークを防ぐために非常に重要なので、セットで覚えておいてくださいね。」
生徒
「クリーンアップを忘れると、ページを移動しても裏側でずっと処理が動き続けちゃう可能性があるんですよね。気をつけます!あと、useEffectの第2引数の空配列[]を忘れると、無限にAPIを叩き続けちゃうこともあるって聞きました…。」
先生
「よく勉強していますね!その通り、依存配列を忘れると再レンダリングのループにハマることがあります。React DevToolsなどを使って、不必要なレンダリングが起きていないかチェックする癖をつけると、よりスキルの高いエンジニアになれますよ。」
生徒
「分かりました!これからは関数コンポーネントを中心に、フックを使いこなせるように練習してみます。Hooksの世界は奥が深そうだけど、シンプルに書けるのが楽しいです!」
先生
「その意気です!もしクラスコンポーネントで作られた古いプロジェクトの改修を頼まれても、今回の知識があれば大丈夫。自信を持ってコードを書いていきましょう!」