Reactアプリケーションを効率よく管理するためには、コンポーネントのライフサイクルを理解することが重要です。ライフサイクルは、コンポーネントが「マウント」されてから「アンマウント」されるまでの一連のプロセスを指します。これにより、コンポーネントの初期化や更新、終了時に特定の処理を行うことが可能になります。この記事では、Reactコンポーネントのライフサイクルに関する基本と、主なライフサイクルメソッドについて解説します。
1. コンポーネントのライフサイクルとは?
Reactコンポーネントは、以下の3つの主要なフェーズを経て動作します。
- マウント(Mounting): コンポーネントが初めてDOMに挿入されるときのフェーズ。
- 更新(Updating): コンポーネントが更新され、再レンダリングされるときのフェーズ。
- アンマウント(Unmounting): コンポーネントがDOMから削除されるときのフェーズ。
Reactでは、これらのフェーズに応じて特定のライフサイクルメソッドを実行し、必要な処理を行うことができます。
2. クラスコンポーネントにおけるライフサイクルメソッド
クラスコンポーネントを使うと、以下のライフサイクルメソッドを活用して、コンポーネントの状態管理やサーバーとのデータ通信を効率化できます。関数コンポーネントでは、useEffectフックを使うことで同じことができますが、ここではクラスコンポーネントに焦点を当てます。
マウントフェーズ
-
componentDidMount(): コンポーネントがDOMにマウントされた直後に呼ばれます。サーバーからのデータフェッチや初期化処理に最適です。
class MyComponent extends React.Component {
componentDidMount() {
// サーバーからデータを取得する例
fetch("/api/data")
.then(response => response.json())
.then(data => {
this.setState({ data });
});
}
render() {
return <div>コンテンツを表示</div>;
}
} 更新フェーズ
-
componentDidUpdate(prevProps, prevState): コンポーネントが更新された後に呼ばれます。propsやstateの変化に基づいて特定の処理を実行したい場合に便利です。
class MyComponent extends React.Component {
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
console.log("カウントが更新されました!");
}
}
render() {
return <div>カウント: {this.state.count}</div>;
}
} アンマウントフェーズ
-
componentWillUnmount(): コンポーネントがアンマウント(DOMから削除)される直前に呼ばれます。タイマーのクリアやサブスクリプションの解除など、クリーンアップ処理に使われます。
class MyComponent extends React.Component {
componentWillUnmount() {
// タイマーを解除する例
clearTimeout(this.timer);
}
render() {
return <div>アンマウントされる前に表示されます</div>;
}
} 3. フックを使った関数コンポーネントのライフサイクル管理
Reactのフック(Hooks)を使えば、関数コンポーネントでもライフサイクルメソッドと同様のことができます。特に**useEffect**フックは、コンポーネントのマウント、更新、アンマウントに関する処理をまとめて管理できます。
useEffectによるマウント、更新、アンマウントの管理
import React, { useState, useEffect } from "react";
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// マウント時に実行される処理
console.log("コンポーネントがマウントされました");
// クリーンアップ関数(アンマウント時に実行される)
return () => {
console.log("コンポーネントがアンマウントされました");
};
}, []); // 空の依存配列を指定すると、マウントとアンマウント時にのみ実行される
useEffect(() => {
// countが更新されるたびに実行される処理
console.log(`カウントが更新されました: ${count}`);
}, [count]); // countの更新時にのみ実行される
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>カウントアップ</button>
</div>
);
}
export default MyComponent; - マウントとアンマウント:
useEffectの第2引数に空の配列[]を渡すと、マウント時に実行され、アンマウント時にクリーンアップ処理が実行されます。 - 更新時の処理:
useEffectの第2引数に[count]を渡すと、countが変わるたびに処理が実行されます。
4. ライフサイクルを活用した実践例
データフェッチのライフサイクル
ライフサイクルメソッドやフックを使って、コンポーネントがマウントされたときにデータをサーバーからフェッチするのが一般的です。以下は、useEffectを使ったデータフェッチの例です。
import React, { useState, useEffect } from "react";
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// データのフェッチ処理
fetch("/api/data")
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
});
// クリーンアップ処理は不要
}, []); // 一度だけ実行される
if (loading) {
return <p>データを読み込み中...</p>;
}
return (
<div>
<h1>データ:</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default DataFetcher; 5. 高度なライフサイクルメソッド
クラスコンポーネントでは、以下のような高度なライフサイクルメソッドも利用できます。ただし、React Hooksが登場してからは、これらのメソッドを使うことはあまり推奨されていません。
-
shouldComponentUpdate(nextProps, nextState): コンポーネントが再レンダリングされるべきかどうかを判断します。パフォーマンス最適化のために使用されます。 -
getDerivedStateFromProps(props, state):propsに基づいて状態を更新する際に使用されます。 -
getSnapshotBeforeUpdate(prevProps, prevState): DOMが更新される前に特定の情報をキャプチャするために使います。
6. ライフサイクル管理のベストプラクティス
- データフェッチはマウント時に行う: APIからデータを取得する場合、
componentDidMountやuseEffectのマウント時に行い、データ取得後に状態を更新して再レンダリングします。 - クリーンアップ処理を忘れない: タイマーやサブスクリプションなどを使用する場合、アンマウント時にクリーンアップを行い、メモリリークを防ぎます。
- 依存配列を正しく設定する:
useEffectの第2引数に正しい依存関係を設定することで、必要なタイミングでのみ処理が実行されるようにします。
まとめ
Reactのコンポーネントライフサイクルを理解することで、コンポーネントの初期化や更新、クリーンアップのタイミングを適切に管理できます。特に、データフェッチやリソースの管理においてライフサイクルを正しく活用することが、効率的なReact開発の鍵となります。useEffectフックを使うことで、関数コンポーネントでも同様の機能を簡単に実現できるので、積極的に利用してみてください。

