Reactではコンポーネントの定義を記述する方法として以下の2つがあります。
・Class Component(クラスコンポーネント)
・Function Component(関数コンポーネント)
React Hooksが導入されるVer16.8以前は関数コンポーネントにはstate(状態)を持たせる処理を行うことができなかったので、クラスコンポーネントを使うことが主流でしたが、現在ではHooksが導入されたことにより、関数コンポーネントでもstateやライフサイクルに相当するものが実装できるようになっていることもあり、React公式では関数コンポーネントを使うことを推奨しているようです。
今回の記事ではクラスコンポーネントと関数コンポーネントの違いと使い分けについて解説していきます。
クラスコンポーネントの基本コード
import React from "react";
class ClassComponent extends React.Component {
render() {
return <div>This is Class Component</div>;
}
}
React.Componentを継承してrenderメソッドでJSXをリターンする構文で記述します。
クラスコンポーネントのライフサイクル
Reactのコンポーネントにはライフサイクルという概念があります。React.Componentを拡張したクラスコンポーネントでは、予め用意されているrender()メソッド等を利用することでライフサイクルの中で任意のタイミングで処理を実行することができます。
公式サイトにて説明されているライフサイクルの図
ライフサイクルには大きく分けて下記の3つの期間が設定されています。
1.Mounting(マウント時)
コンポーネントのHTMLがレンダリングされるまでの期間
2.Updating(更新時)
コンポーネントのHTMLがレンダリングされた後の期間
3.Unmounting(マウント解除時)
現在表示されているコンポーネントから他のコンポーネントへ切り替える前に、現在のコンポーネントを破棄するタイミングの期間
ライフサイクルメソッド
上記のライフサイクルにはそれぞれ付随したライフサイクルメソッドというものがあり、ライフサイクルの処理の順番で実行されます。
constructor()
Mounting時に一番最初に呼ばれるメソッドです
getDerivedFromProps()
render()が呼ばれる前にstateの更新があるかどうかを確認します
render()
ReactがJSXコードを解析して仮想DOMを構築します
componentDidMount()
1回目のrender()が呼ばれた時に1度だけ呼ばれます
getDerivedStateFromProps()
Updating 時に一番最初に呼ばれるメソッドです
shouldComponentUpdate()
コンポーネントの評価と再レンダリングを継続するかどうかを判定します
render()
ReactがJSXコードを解析して仮想DOMを構築します
getSnapshotBeforeUpdate()
Updatingが発生する直前のスクロールを位置などの値を引き継ぎます
componentDidUpdate()
Updating が完了した際に呼ばれるメソッドです
componentWillUnmount()
コンポーネントがUnmountされるときに呼ばれるメソッドです
クラスコンポーネントを使うメリット
1.ライフサイクルで細かい処理を入れることができる
2.メソッドが多くてもコードの見通しが良い
関数コンポーネントの基本コード
import React from "react";
const Component = () => {
return <div>This is Functional Component</div>;
};
関数コンポーネントのライフサイクル(Hooks)
useState
useStateフックは、React本体に関数コンポーネント専用の保存領域を作成してもらい、そこにあるデータを読み書きできるフックです
useEffect
「副作用を実行するフック」とも呼ばれており、コンポーネントのレンダリング後に実行されます。
useMemo
useMemoフックは単純に値を保存するためのフックです。useStateと違い、更新関数はありません。
useCallback
useMemoは何でもキャッシュすることができるので、例えば関数をキャッシュすることができます。
関数コンポーネントを使うメリット
1.クラスコンポーネントに比べて簡潔に書ける
2.React.createElement()と比べると45%ほどレンダーが速い
クラスコンポーネントで記述した例
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class HelloComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "Hoge"
};
}
render() {
return (
<div className="App">
<h1>React Class Component</h1>
<h2>
Hello {this.state.name} ! {this.props.message}
</h2>
<input
type="text"
value={this.state.name}
onChange={(e) =>
this.setState({
name: e.target.value
})
}
/>
</div>
);
}
}
let dom = document.getElementById("root");
ReactDOM.render(<HelloComponent message="by Class" />, dom);
関数コンポーネントで記述した例
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const HelloComponent = (props) => {
const [name, setName] = useState("World");
return (
<div className="App">
<h1>React Class Component</h1>
<h2>
Hello {name} ! {props.message}
</h2>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
);
};
let dom = document.getElementById("root");
ReactDOM.render(<HelloComponent message="by Function" />, dom);
Propsによるデータの受け渡し
クラスコンポーネントの場合
this.props.XXXと記述することで利用可能
関数コンポーネントの場合
関数定義の引数としてpropsを定義することで利用可能
stateの初期設定
クラスコンポーネントの場合
コンストラクタ内でステートの初期設定を行います
関数コンポーネントの場合
Hooksの機能であるuseStateを使って初期設定を行います
stateの更新処理
クラスコンポーネントの場合
steteを更新するためのsetStateを使って更新します
this.setState({XXX: value})
関数コンポーネントの場合
useSteateで定義されたsetXXX関数を経由して値を変更します
stateの更新処理(差分更新)
クラスコンポーネントの場合
this.setStateがオブジェクトの場合でも、オブジェクト内の更新する変数のみ更新することが可能です
<Form.Control
value={this.state.name}
onChange={(e) => this.setState({
name: e.target.value
})}
/>
関数コンポーネントの場合
useStateのsetXXXはstateがオブジェクトの場合はオブジェクト内の全ての変数を更新する記述をする必要があります。
<Form.Control
value={person.name}
onChange={(e) => setPerson({
name: e.target.value,
email: "",
address: "",
age: 0
})}
/>
クラスコンポーネントを使うケース
下記のケースに該当する場合はクラスコンポーネントを使うとよいでしょう。
但しクラスの場合はthisが多用されることになるので、ソース内の混乱が発生することになりがちなので、コーディングルールには気をつけたほうがいいです。
・Lifecycle methodを使う必要がある場合
・ 複雑なstateを持たせる場合
・ メソッドが多い場合
関数コンポーネントを使うケース
上記の「 クラスコンポーネントを使うケース 」以外は全て関数コンポーネントでいいと思います。
(React公式でも推奨は関数コンポーネントのほうなので)
特に渡したい引数であるpropsを渡して表示するコンポーネントであれば関数コンポーネントのほうにメリットがあります。
関数コンポーネントの記述は短くシンプルに記述することが出来るので、アプリケーションの全体設計やメンテナンスの面では関数コンポーネントをメインで使っていくことがいいでしょう。
また、クラスコンポーネントは廃止されておらず継続的に使えますので、基本的には関数コンポーネントをメインで使いつつ、必要に応じてクラスコンポーネントを使っていくようにすると良いと思います。
45% Faster React Functional Components, Now
https://medium.com/missive-app/45-faster-react-functional-components-now-3509a668e69f
Classコンポーネントのライフサイクル(React公式)
https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/