こんにちは!
React でコンポーネントを作成する方法は2つあります。Class component と Functional component です。この記事では、この2つの作成方法の違いと、プロジェクトに適した方法の選び方を紹介します。
コンポーネントとは、React のアプリケーションの中心となるビルディング・ブロックです。これにより、UI をコードを再利用して一つひとつ個別に作業できるように分割して作業できます。
React ではコンポーネントを作成するには、Class component と Functional component の2つの方法があります。React 開発者だけでなくReact の初心者でも、React の2種類のコンポーネントの違いが分かるように説明します。
この記事では、Class component と Functional component の違いと、選び方を解説します。
Class component は、ステートフル・コンテナコンポーネントです。React ライブラリのコンポーネントクラスを拡張する通常の Javascript の ES6 クラスです。ステートフル・コンポーネントと呼ばれているのは、ステートの変更とコンポーネント・ロジックの実行をコントロールしているからです。ほかにも、React のコンポーネントが生成されてから破棄されるまでのライフサイクルメソッドのすべてのフェーズにアクセスできます。
新機能の React Hooks が登場する前は、Class component でしか、動的で再利用可能なコンポーネントを作成することができませんでした。ライフサイクルメソッドとすべての React 機能にアクセスする唯一の方法でした。
Class component の使い方を説明するために、ユーザーが数値を増減できるシンプルなカウンター・コンポーネントを作成しましょう。この例では、ライフサイクルメソッドも少し紹介します。
// demonstrating a Class component
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
this.setState({
count: this.state.count + 1
});
}
handleIncrement = () => {
this.setState({
count: this.state.count + 1
});
};
handleDecrement = () => {
this.setState({
count: this.state.count - 1
});
};
render() {
return ( < div className = "counter" > < h1 className = "count" > {
this.state.count
} < /h1> < button type = "button"
onClick = {
this.handleIncrement
} > Increment < /button> < button type = "button"
onClick = {
this.handleDecrement
} > Decrement < /button> < /div>);
}
}
export default Counter;
このコンポーネントの例では、カウントを0で開始したくないため、コンストラクタで初期のステートを設定し、ライフサイクルメソッドの componentDidMount を使用して、コンポーネントがマウントされたときにステートを0から1に設定します。
カウントの0の後、すぐに1が表示されます。コンポーネントが最初にレンダリングされると、初期のステートによって0のカウントが即時に表示されます。コンポーネントがマウントされた後、componentDidMount は実行され、新しいカウント状態が1に設定されます。
また、コンポーネントに2つの機能(handleIncrementとhandleDecrementの関数)を実行し、ユーザーが increment(増加)または decrement(減少)ボタンをクリックしたときにカウンタを増減できます。
クラスベースのコンポーネントについては、この動的コンポーネントを作成するためにいくつかの手順があることが分かると思います。コンストラクタと render メソッドでクラスを作成しました。コンストラクタの this.state ステートメントで初期ステートを設定します。this.setState を使用して、componentDidMount などのステートとライフサイクルメソッドを更新し、コンポーネントがマウントされたときにステートがすぐに更新されます。
では、Class component を Functional component に変換して、違いをみてみましょう。
関数コンポーネントは JavaScript の機能のことです。React 16.8 で Hooks が登場する前は、DOM にレンダリングされるデータのみを受け返ししていたため、ステートレス・プレゼンテーションコンポーネントと呼ばれていました。
以前は、ステートや React のライフサイクルメソッドなどの React の機能にアクセスするには、クラスコンポーネントしか方法がありませんでした。しかし Hooks を使用すると、ステートやその他の React の機能を実行でき、Functional component を使用してUI全体を書くことができるようになりました。
Hooks を使用することで、React でコンポーネントをより簡単に作成できます。React には、ステート(useState)とuseEffectの2つのよく使用される Hooks があります。次の例では、両方の使用方法を紹介します。React を初めて使用する場合は、こちらをご覧ください。
Functional component と Class component の違いが理解できるよう、以前に Class component で作成したカウンター・コンポーネントを Functional component に置き換えてみましょう。
// demonstrating a functional component
const App = () => {
const [count, setCount] = useState(0);
useEffect(() => setCount((currentCount) => currentCount + 1), []);
const handleIncrement = () => setCount((currentCount) => currentCount + 1);
const handleDecrement = () => setCount((currentCount) => currentCount - 1);
return ( < div className = "counter" > < h1 className = "count" > {
count
} < /h1> < button type = "button"
onClick = {
handleIncrement
} > Increment < /button> < button type = "button"
onClick = {
handleDecrement
} > Decrement < /button> < /div>);
};
export default App;
カウンター・コンポーネントの動作は理解していると思うので、Class component と比較して Functional component でどのように実行したか見てみましょう。
まず、クラスではなく関数なので、コンストラクタやレンダリングメソッドは必要ありません。以前は Class component でしかできませんでしたが、Hooks を使用すると、React Library の必要な機能をすべて統合できます。
そのため、useState を使用し、Functional component でステートを追加できます。上で示したように、React からuseState をインポートして、カウントの初期状態を0に設定しました。useState の hook は、現在のステートとステートを更新する関数の2つを送り返します。this.state と this.setState を使用してクラスコンポーネントにステートを実行する方法を比較してみましょう。次のコードをご覧ください。
Const [count, setCount] = useState(0);
State hook は、現在のカウントとステート・カウントを更新する関数である setCount の2つを送り返します。Functional component でステートを実行するのは、とても簡単です。
Class component を使用した経験がある場合は、componentDidMount や componentWillUnmount などの React ライフサイクルメソッドに精通していると思います。以前は、Functional component ではこれらの機能を使えませんでしたが、useEffectのhook を使用すれば、React のライフサイクルメソッドを実行できます。useEffectを使用すると、Functional component でuseEffectを実行できます。useEffect は、componentDidMount、componentDidUpdate、componentWillUnmount の組み合わせたような機能だと思ってください。
上の Functional component の例では、Class component で使用した componentDidMount のようなライフサイクルメソッドを実行するために、useEffect のフックを使用しました。
useEffect(() => setCount((currentCount) => currentCount + 1), []);
この useEffect を使用すると、レンダリング後にコンポーネントが次の動作が必要であることを React に通知します。その後、React はあなたが送った関数を記憶し、DOMの更新を実行した後、呼び出します。
したがって、上の例ではカウント・ステートの変数を設定し、useEffectを使用する必要があることを React に伝えています。関数は useEffect の hook に送られます。送ったuseEffectの関数により、私たちはuseEffect内のステート・カウントを更新しました。それによって、カウント0と1が交互に表示されます。コンポーネントの最初のレンダリングは、初期ステートなので0の数を表示しています。その後、コンポーネントがマウントされると、useEffect の hook が実行され、新しいカウント・ステートの1に更新されます。
これは、コンポーネントがマウントかアンマウントされたときだけ、useEffect hook がトリガーされるようにするためです。試しに2番目の引数を削除してみると、カウントを1増やす無限のループが起こります。ステートが変更された後に、useEffect hook が常に実行されるからです。useEffect hook は別のステートの変化をトリガーするため、カウントを増やす変化が何度も実行されます。
たくさん説明を加えましたが、React を初めて使用する人にも理解してもらえると嬉しいです。
上の例から分かるように、Class component と Functional component の大きな違いは構文です。個人的には、Functional component は Class component に比べて理解しやすいと感じますが、Java のようなオブジェクト指向プログラミングを得意とする開発者は感じ方が違うかもしれません。
Class component はES6クラスの構文を使用し、React の要素を送り返すレンダリングメソッドを使い、React コンポーネントを拡張します。一方、Hooks を使用した Functional component は、React 要素も送り返すためにJavaScript関数を使います。
Hooks が導入される前、Functional component はステートレスでしたが、React 16.8以降、useState の hook を使用して Class component と同じように、ステートフル・コンポーネントを作成できます。
また、ライフサイクルメソッドに関しても、useEffect の hook を利用して、componentDidMount・componentDidUpdate・componentWillUnmountなどのライフサイクルメソッドと同じuseEffectを、Class component と組み合わせながら、Functional component でも作成できます。
React のコンポーネントのステートやライフサイクルメソッドの詳細については、こちらをご覧ください。
2つのコンポーネントの違いと、React でコンポーネントを構築する際にどのように使用されるかを説明しました。このセクションでは、Class component と Functional component とどちらを選べばいいのか説明します。また、新しいReact アプリケーションを作る場合は、Functional component をおすすめする理由を説明します。
しかし、2つのコンポーネントの選び方は簡単に決められません。経験上、React 開発者はそれぞれ好みのコンポーネントがあり、意見が分かれます。
選び方を紹介する前に、Class component を置き換えるために Functional component を導入した理由を見てみましょう。React チームによると、Functional component に Hooks を導入した動機が関わっています。
動機については、React Docs に詳しく記載されています。
React チームは、新しいアプリを Functional component と Hooks で構築することを推奨しました。したがって、チームが Class component を積極的に希望しない限り、新しい React プロジェクトで作業するときは、Functional componentのアプローチを検討したほうがいいです。しかし React を初めて使用する場合は、Class component の知識を持っていると便利です。Class component で書かれたレガシーコードベースを Functional component に移行する必要があるかもしれません。
Class component と Functional component の両方で作業した私の経験を共有したいと思います。私は次の理由でFunctional component を推奨します。
さらに React チームは最近、React ドキュメントにて、Functional component と Hooks の使用に焦点を当てて説明すると発表しました。しかし今回のアップデートで、Class component が使用できなくなるわけではなく、今後も続けて使用できます。Class component のドキュメントも存在するので、開発者が今後も参考にできます。
この記事では、React でコンポーネントを構成する2つのアプローチの違いを説明しました。Class component は React のコンポーネントライブラリを拡張して、ステートフルコンポーネントを作成する通常のES6クラスです。それに対して、Hooks と Functional component を使用して、ステートフルまたはプレゼンテーションコンポーネントを構築できます。また、2つのコンポーネントの選び方と、React プロジェクトでは Functional component を推奨する理由を説明しました。参考にしてもらえると嬉しいです。