歴史で読み解くReact:なぜ私たちはクラスを書かなくなったのか

アイキャッチ画像

Reactの関数コンポーネントとクラスコンポーネントの違いを、歴史とともに振り返る

Reactでコードを書くとき、今では当たり前のように、そして息を吸うように使われている「関数コンポーネント(Functional Component)」。

画面の描画から複雑な状態管理、非同期処理の制御にいたるまで、すべてをスマートな関数として書き下すのが現代のスタンダードです。

しかし、Reactの歴史を少しだけ、あるいは思い切って10年ほど巻き戻してみると、そこには全く異なる風景が広がっていました。

かつては「クラスコンポーネント」こそがフロントエンド開発の王座に君臨する絶対的な主役であり、当時の関数コンポーネントは「state(内部状態)を持たず、ただ受け取ったデータを画面に表示するだけの、お飾り的なオマケ(Stateless Functional Component)」という、どこか肩身の狭い扱いに甘んじていたのです。

「ただの表示用パーツ」に過ぎなかった小さな関数が、いかにして幾多の課題を乗り越え、クラスコンポーネントから王座を奪い取る「天下統一」を果たしたのか?

その劇的なパラダイムシフトの変遷を、当時の開発現場の空気感とともに、歴史のタイムラインに沿ってもう少し深く紐解いてみましょう。

黎明期(2013年〜2015年):クラスコンポーネントの全盛期

Reactが世に発表された当初、コンポーネントを作るための主要な手段はクラスコンポーネント(ES6の class 構文や React.createClass)でした。

当時のコードは、このような書き方がスタンダードでした。

class MyComponent extends React.Component {
 constructor(props) {

    super(props);

    this.state = { count: 0 };

  }

  render() {

    return <div>{this.state.count}</div>;

  }

}
  • 当時の立ち位置:画面の描画(render)だけでなく、内部の状態管理(state)や、データ取得・DOM操作といったライフサイクルイベント(componentDidMount や componentDidUpdate など)を扱うには、クラスを使うのが「唯一の方法」でした。
  • 初期の関数コンポーネント:この頃の関数コンポーネントは、ただ props を受け取ってJSXを返すだけの「純粋な関数」に過ぎず、stateやライフサイクルを持てなかったため、使い道が限定されていました。

抱えていた「モヤモヤ」(クラスコンポーネントの限界)

長らくクラスコンポーネントが主流として君臨していましたが、現場のエンジニアの間ではいくつかの「扱いにくさ(辛み)」が共有されるようになっていました。

  1. this の迷宮:JavaScriptの this の挙動は複雑で、イベントハンドラーに this をバインド(.bind(this))し忘れてバグを生むことが多発しました。
  2. ライフサイクルメソッドの肥大化と重複:「データを取得する」という1つの目的なのに、初期化は componentDidMount、更新時は componentDidUpdate と、同じロジックを複数のメソッドにバラバラに書かなければいけませんでした。
  3. ロジックの再利用の難しさ(HOCやRender Propsの苦悩):「複数のコンポーネントで同じ状態管理のロジックを使いたい」と思ったとき、Higher-Order Components (HOC) や Render Props という複雑なデザインパターンを使わざるを得ず、コードが「ラッパーの階層」で深くネスト(インデントが右に寄りまくる現象)してしまいました。

転換点(2018年):React Hooks の衝撃

この停滞感を打破したのが、2018年に発表された「React Hooks(useState / useEffectなど)」です。

これにより、関数コンポーネントでもstateやライフサイクルと同等の機能を安全に扱えるようになりました。

import React, { useState, useEffect } from 'react';

function MyComponent() {

  const [count, setCount] = useState(0);

  useEffect(() => {

    // ライフサイクルの処理をここに集約できる

  }, []);

  return <div>{count}</div>;

}

歴史的な大逆転:「関数で書けるなら、ややこしい class も this も要らないよね」ということで、エコシステム全体が一気に「関数コンポーネント+Hooks」へと舵を切りました。
コードの行数が劇的に減り、ロジックの再利用(カスタムHooksの作成)も驚くほど簡単になりました。

現代(2020年以降〜):関数コンポーネントの完全な勝利

現在、React公式ドキュメントでも関数コンポーネントが第一推奨とされており、クラスコンポーネントは「過去の遺産(レガシーコードの維持に必要なもの)」という位置づけに変化しています。

決定的な違いのまとめ

比較項目クラスコンポーネント (Class)関数コンポーネント + Hooks (Functional)
誕生の背景React初期から存在する伝統的な書き方後から追加された現代のスタンダード
構文と thisclass 構文が必須。this の制御が必要シンプルなJavaScriptの関数。this は不要
状態管理 (State)this.state / this.setStateuseState フックを使用
ライフサイクルcomponentDidMount 等をバラバラに記述useEffect などにロジックを集約・分離できる
コードの再利用HOCやRender Propsで複雑化しがちカスタムHooksでスマートに再利用可能

まとめ:なぜ歴史を振り返るのか

Reactにおける関数コンポーネントとクラスコンポーネントの変遷は、単なる「便利な新機能が出た」という浅い話でもなければ、どちらの文法が読みやすいかといった「書き方の好みの問題」でもありません。

それは、「JavaScriptという言語が持つ独特の制約や、オブジェクト指向的な設計の呪縛(this のバインドや複雑なライフサイクル)から、純粋な関数とクロージャの仕組みをフル活用したクリーンで本質的な設計思想へのパラダイムシフト」そのものの歴史です。

レガシーなコードベースに出くわしたとき、あるいは一見すると難解なオープンソースのカスタムHooksやライブラリの内部実装を紐解くとき。

「なぜこのコードはこういう書き方をしているのか?」という背後にある歴史の文脈と、先人たちが乗り越えようとした痛みの記憶を知っていると、日々の見慣れたReactのコードが、単なる文字列ではなく「技術の進化の足跡」として少しだけ深く、そして愛おしく見えてくるはずです!