ReactJS - コンポーネントのライフサイクル

こんにちは、将来のReact開発者さんたち!今日は、Reactコンポーネントのライフサイクルを楽しい旅に連れて行きます。プログラミングが初めての方でも心配しないでください - 私があなたの親切なガイドとして、すべてをステップバイステップで説明します。このチュートリアルの終わりまでに、Reactコンポーネントがどのようにして生まれ、成長し、最終的にさよならを言うかをしっかりと理解するでしょう。さあ、始めましょう!

ReactJS - Component Life Cycle

コンポーネントライフサイクルとは?

コードに飛び込む前に、「ライフサイクル」とは何を意味するか話しましょう。私たち人間は人生の különböző段階(誕生、成長、そして、うーん、あなたも知っているでしょう...)を通りますが、Reactコンポーネントも自分たちのライフステージを持っています。これらのステージはコンポーネントライフサイクルと呼ばれます。

Reactコンポーネントを仮想的なペットと考えてみてください。最初に作成するときに生まれます。それから、あなたとのインタラクションで成長し変わります。最後に、もう必要ないときには去ります。このライフサイクルを理解することは、動的で効率的なReactアプリケーションを作成するためには不可欠です。

コンポーネントの主要な3つの段階

Reactコンポーネントは以下の3つの主要な段階を通ります:

  1. モウント(誕生)
  2. 更新(成長)
  3. アンマウント(さよなら)

これらの各段階とそれに関連するメソッドについて探ってみましょう。

1. モウント段階

これは、私たちのコンポーネントが生まれ、DOM(ドキュメントオブジェクトモデル - ウェブページの家系図と考えてください)に追加されるときです。

この段階の主要なメソッド:

メソッド 説明
constructor() コンポーネントのコンストラクタ、モウントされる前に呼び出されます
render() 実際にコンポーネントをレンダリングするメソッド
componentDidMount() コンポーネントがDOMにモウントされた後に呼び出されます

簡単な例を見てみましょう:

import React, { Component } from 'react';

class BabyComponent extends Component {
constructor(props) {
super(props);
this.state = { message: "I'm just born!" };
console.log("Constructor: Hello, I'm being created!");
}

componentDidMount() {
console.log("componentDidMount: I'm now in the DOM!");
}

render() {
console.log("Render: I'm being rendered!");
return <h1>{this.state.message}</h1>;
}
}

export default BabyComponent;

この例では、私たちのBabyComponentは誕生段階を経験します。まずconstructorが呼び出され、初期状態が設定されます。その後renderが呼び出され、実際のDOM要素が作成されます。最後に、componentDidMountが呼び出され、私たちのコンポーネントが完全に誕生し、DOMに追加されたことが示されます。

2. 更新段階

この段階は、コンポーネントの状態が変更されたり、新しいプロップを受け取ったりしたときに発生します。

この段階の主要なメソッド:

メソッド 説明
shouldComponentUpdate() コンポーネントが再レンダリングするべきかを決定します
render() 更新されたデータでコンポーネントを再レンダリングします
componentDidUpdate() コンポーネントが更新された後に呼び出されます

前の例を拡張してみましょう:

import React, { Component } from 'react';

class GrowingComponent extends Component {
constructor(props) {
super(props);
this.state = { age: 0 };
}

componentDidMount() {
this.ageInterval = setInterval(() => {
this.setState(prevState => ({ age: prevState.age + 1 }));
}, 1000);
}

shouldComponentUpdate(nextProps, nextState) {
return nextState.age % 5 === 0; // 5年ごとにだけ更新
}

componentDidUpdate() {
console.log(`I just turned ${this.state.age}!`);
}

render() {
return <h1>I am {this.state.age} years old</h1>;
}

componentWillUnmount() {
clearInterval(this.ageInterval);
}
}

export default GrowingComponent;

この例では、私たちのGrowingComponentは1秒ごとに「年を取ります」。shouldComponentUpdateメソッドは、5年ごとにだけバースデーを祝うように設定しています。コンポーネントが更新するときには、componentDidUpdateがバースデーメッセージをログします。

3. アンマウント段階

これは、コンポーネントがDOMから削除されるさよなら段階です。

この段階の主要なメソッド:

メソッド 説明
componentWillUnmount() コンポーネントがアンマウントされ、破壊される直前に呼び出されます

前のGrowingComponentの例で使用したように、componentWillUnmountメソッドを使用してインターバルをクリアし、メモリリークを防ぎます。

ライフサイクルAPIの動作例

さあ、これらすべてをより複雑な例にまとめてみましょう。シンプルな「気分トラッカー」アプリを作成し、すべてのライフサイクルメソッドをデモンストレーションします。

import React, { Component } from 'react';

class MoodTracker extends Component {
constructor(props) {
super(props);
this.state = { mood: 'neutral', intensity: 5 };
console.log('Constructor: Mood Tracker is being created');
}

componentDidMount() {
console.log('ComponentDidMount: Mood Tracker is now in the DOM');
this.moodInterval = setInterval(() => {
const moods = ['happy', 'sad', 'excited', 'nervous', 'neutral'];
const newMood = moods[Math.floor(Math.random() * moods.length)];
this.setState({ mood: newMood });
}, 5000);
}

shouldComponentUpdate(nextProps, nextState) {
return this.state.mood !== nextState.mood;
}

componentDidUpdate() {
console.log(`Mood updated to: ${this.state.mood}`);
}

componentWillUnmount() {
console.log('ComponentWillUnmount: Goodbye Mood Tracker!');
clearInterval(this.moodInterval);
}

handleIntensityChange = (e) => {
this.setState({ intensity: e.target.value });
}

render() {
console.log('Render: Mood Tracker is rendering');
return (
<div>
<h1>Current Mood: {this.state.mood}</h1>
<input
type="range"
min="1"
max="10"
value={this.state.intensity}
onChange={this.handleIntensityChange}
/>
<p>Intensity: {this.state.intensity}</p>
</div>
);
}
}

export default MoodTracker;

このMoodTrackerコンポーネントは、私たちが話したすべてのライフサイクルメソッドをデモンストレーションしています。5秒ごとにランダムな気分に変更し、ユーザーが気分の強度を調整できるようにしています。

費用管理アプリケーションでのライフサイクルAPIの使用

次に、実際のアプリケーションである費用管理アプリケーションでこれらのライフサイクルメソッドをどのように使用するか考えてみましょう。

import React, { Component } from 'react';

class ExpenseManager extends Component {
constructor(props) {
super(props);
this.state = { expenses: [], total: 0 };
}

componentDidMount() {
// APIから費用データを取得するのをシミュレート
setTimeout(() => {
const fetchedExpenses = [
{ id: 1, description: 'Groceries', amount: 50 },
{ id: 2, description: 'Gas', amount: 30 },
{ id: 3, description: 'Movie tickets', amount: 20 },
];
this.setState({ expenses: fetchedExpenses }, this.calculateTotal);
}, 1000);
}

shouldComponentUpdate(nextProps, nextState) {
// 合計が変更された場合にのみ更新
return this.state.total !== nextState.total;
}

componentDidUpdate() {
console.log(`Total expenses updated: $${this.state.total}`);
}

calculateTotal = () => {
const total = this.state.expenses.reduce((sum, expense) => sum + expense.amount, 0);
this.setState({ total });
}

render() {
return (
<div>
<h1>Expense Manager</h1>
<ul>
{this.state.expenses.map(expense => (
<li key={expense.id}>{expense.description}: ${expense.amount}</li>
))}
</ul>
<h2>Total: ${this.state.total}</h2>
</div>
);
}
}

export default ExpenseManager;

このExpenseManagerコンポーネントでは:

  1. componentDidMountを使用して、コンポーネントが最初に読み込まれたときに费用データをAPIから取得するのをシミュレートします。
  2. shouldComponentUpdateは、合計が変更された場合にのみ再レンダリングします。
  3. componentDidUpdateは、合計が更新されたときに新しい合計をログします。

これらのライフサイクルメソッドを活用することで、効率的で反応の良い费用管理アプリケーションを作成できます。

コンポーネントライフサイクルを理解することは、効率的なReactアプリケーションを構築するために非常に重要です。特定のアクションがいつ発生するかを制御し、パフォーマンスを最適化し、リソースを効果的に管理することができます。これらの概念を練習し続けることで、すぐに複雑で動的なReactアプリケーションを簡単に作成できるようになります!

Credits: Image by storyset