React クラスコンポーネント
React 16.8 以前は、React コンポーネントで State(ステート) や Lifecycle(ライフサイクル) を管理する唯一の方法はクラスコンポーネントでした。当時、関数コンポーネントは「ステートレス(状態を持たない)」ものと見なされていました。
Hooks(フック) の導入により、現在では関数コンポーネントはクラスコンポーネントとほぼ同等の機能を持ちます。その差は非常にわずかであり、現在の React 開発においてクラスコンポーネントを新しく作成する必要性はほとんどありません。
関数コンポーネントが推奨されていますが、React からクラスコンポーネントを削除する計画は現時点ではありません。
このセクションでは、React におけるクラスコンポーネントの使用方法の概要を説明します。必要に応じてこのセクションをスキップし、関数コンポーネントの学習に進んでも構いません。
1. クラスコンポーネントの作成
React コンポーネントを作成する際、コンポーネント名は必ず大文字で始める必要があります。
クラスコンポーネントは extends React.Component を含める必要があります。この記述により React.Component を継承し、コンポーネントは React.Component の持つさまざまな機能にアクセスできるようになります。
また、クラスコンポーネントには HTML を返す render() メソッドが必須です。
1.1 Car クラスコンポーネントの作成例
class Car extends React.Component {
render() {
return <h2>こんにちは、私は車です!</h2>;
}
}これで、<h2> 要素を返す Car というコンポーネントが作成されました。
アプリケーション内でこのコンポーネントを使用するには、通常の HTML と同様の構文 <Car /> を使用します。
1.2 コンポーネントのレンダリング
createRoot(document.getElementById('root')).render(
<Car />
);2. コンポーネントのコンストラクタ (Constructor)
コンポーネント内に constructor() 関数がある場合、その関数はコンポーネントが初期化される際に呼び出されます。
Constructor(コンストラクタ) は、コンポーネントのプロパティを初期化する場所です。
React では、コンポーネントのプロパティは state という名前のオブジェクト内に保持する必要があります。state については、このチュートリアルの後半で詳しく説明します。
また、コンストラクタ内では super() ステートメントを含めることで、親コンポーネント(React.Component)の継承を遵守します。これにより親のコンストラクタ関数が実行され、コンポーネントは React.Component のすべての機能を使用できるようになります。
2.1 コンストラクタでカラープロパティを追加する例
class Car extends React.Component {
constructor() {
super();
this.state = { color: "赤" };
}
render() {
return <h2>私は車です!</h2>;
}
}2.2 render 関数内で state の値を使用する
class Car extends React.Component {
constructor() {
super();
this.state = { color: "赤" };
}
render() {
return <h2>私は {this.state.color} の車です!</h2>;
}
}3. プロップス (Props)
コンポーネントのプロパティを扱うもう一つの方法が Props(プロップス) です。
Props は関数の引数のようなもので、HTML の属性としてコンポーネントに渡されます。
3.1 属性を介して Props を渡す例
class Car extends React.Component {
render() {
return <h2>私は {this.props.color} の車です!</h2>;
}
}
createRoot(document.getElementById('root')).render(
<Car color="赤"/>
);3.2 コンストラクタ内での Props
コンポーネントにコンストラクタ関数がある場合、Props は常にコンストラクタに渡され、さらに super(props) メソッドを介して React.Component に渡される必要があります。
class Car extends React.Component {
constructor(props) {
super(props);
}
render() {
return <h2>私は {this.props.model} です!</h2>;
}
}
createRoot(document.getElementById('root')).render(
<Car model="マスタング"/>
);4. コンポーネントのネストとファイル分割
他のコンポーネントの中でコンポーネントを参照したり、ファイルを分割して管理したりすることができます。
4.1 コンポーネント内のコンポーネント
class Car extends React.Component {
render() {
return <h2>私は車です!</h2>;
}
}
class Garage extends React.Component {
render() {
return (
<div>
<h1>私のガレージには誰が住んでいる?</h1>
<Car />
</div>
);
}
}4.2 コンポーネントの外部ファイル化
再利用性を高めるため、コンポーネントを別のファイルに保存します。ファイル拡張子は .jsx とし、先頭で React をインポートし、末尾で export default を記述します。
Vehicle.jsx
import React from 'react';
class Car extends React.Component {
render() {
return <h2>こんにちは、私は車です!</h2>;
}
}
export default Car;main.jsx(インポートして使用)
import { createRoot } from 'react-dom/client'
import Car from './Vehicle.jsx';
createRoot(document.getElementById('root')).render(
<Car />
);5. クラスコンポーネントの State(状態管理)
React のクラスコンポーネントには、組み込みの state オブジェクトがあります。state オブジェクトは、そのコンポーネントに属するプロパティ値を保存する場所です。state オブジェクトが変更されると、コンポーネントは再レンダリング(Re-render)されます。
5.1 state オブジェクトの初期化
state はコンストラクタ内で初期化します。
class Car extends React.Component {
constructor(props) {
super(props);
this.state = { brand: "フォード" };
}
render() {
return (
<div>
<h1>私の車</h1>
</div>
);
}
}5.2 複数のプロパティを持つ state
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "フォード",
model: "マスタング",
color: "赤",
year: 1964
};
}
render() {
return (
<div>
<h1>私の {this.state.brand}</h1>
<p>
これは {this.state.year} 年製の {this.state.color} の
{this.state.model} です。
</p>
</div>
);
}
}5.3 state オブジェクトの変更
state オブジェクト内の値を変更するには、this.setState() メソッドを使用します。
値が変更されると、コンポーネントは再レンダリングされ、出力が新しい値に基づいて更新されます。
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "フォード",
model: "マスタング",
color: "赤",
year: 1964
};
}
changeColor = () => {
this.setState({ color: "青" });
}
render() {
return (
<div>
<h1>私の {this.state.brand}</h1>
<p>
色は {this.state.color} です。
</p>
<button
type="button"
onClick={this.changeColor}
>色を変更する</button>
</div>
);
}
} 重要:state オブジェクトを変更する際は必ず setState() を使用してください。これにより、React が更新を検知し、render() メソッド(および他のライフサイクルメソッド)を呼び出すことが保証されます。
6. コンポーネントのライフサイクル (Lifecycle)
React の各コンポーネントには、3 つの主要なフェーズで監視および操作できる Lifecycle(ライフサイクル) があります。
3 つのフェーズとは、Mounting(マウンティング)、Updating(アップデーティング)、Unmounting(アンマウンティング) です。
6.1 Mounting (マウンティング)
Mounting とは、要素を DOM に配置することを意味します。
コンポーネントがマウントされる際、React は以下の 4 つのメソッドをこの順序で呼び出します。
constructor()getDerivedStateFromProps()render()componentDidMount()
6.1.1 constructor
コンポーネントが初期化される際、最初に呼び出されます。初期 state やその他の初期値を設定するのに適した場所です。必ず最初に super(props) を呼び出してください。
6.1.2 getDerivedStateFromProps
要素を DOM にレンダリングする直前に呼び出されます。Props に基づいて state を設定する場合に使用します。
6.1.3 render
必須のメソッドであり、実際に HTML を DOM に出力します。
6.1.4 componentDidMount
コンポーネントがレンダリングされた直後に呼び出されます。すでに要素が DOM に配置されている必要がある処理(API 呼び出しやタイマー設定など)を実行します。
class Header extends React.Component {
constructor(props) {
super(props);
this.state = { favoritecolor: "赤" };
}
componentDidMount() {
setTimeout(() => {
this.setState({ favoritecolor: "黄色" })
}, 1000)
}
render() {
return (
<h1>私の好きな色は {this.state.favoritecolor} です</h1>
);
}
}6.2 Updating (アップデーティング)
コンポーネントの state や props に変更があったとき、Updating フェーズが発生します。
更新時には以下の 5 つのメソッドが順に呼び出されます。
getDerivedStateFromProps()shouldComponentUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate()
6.2.1 shouldComponentUpdate
React がレンダリングを続行すべきかどうかの真偽値(Boolean)を返します。デフォルトは true です。
6.2.2 getSnapshotBeforeUpdate
更新直前の props や state にアクセスできます。更新後でも、更新前の値を確認することが可能です。これを使用する場合は componentDidUpdate() も定義する必要があります。
6.2.3 componentDidUpdate
コンポーネントが DOM 内で更新された直後に呼び出されます。
class Header extends React.Component {
constructor(props) {
super(props);
this.state = { favoritecolor: "赤" };
}
componentDidMount() {
setTimeout(() => {
this.setState({ favoritecolor: "黄色" })
}, 1000)
}
getSnapshotBeforeUpdate(prevProps, prevState) {
document.getElementById("div1").innerHTML =
"更新前のお気に入りは " + prevState.favoritecolor + " でした";
}
componentDidUpdate() {
document.getElementById("div2").innerHTML =
"更新後のお気に入りは " + this.state.favoritecolor + " です";
}
render() {
return (
<div>
<h1>私の好きな色は {this.state.favoritecolor} です</h1>
<div id="div1"></div>
<div id="div2"></div>
</div>
);
}
}