logo

鎌イルカのクラフト記

article icon

React勉強会資料 導入編

はじめに

この記事はReactを学び始めるジュニアエンジニア向けの勉強会資料です。「なぜReactが生まれたのか」「何が革新的だったのか」を理解することで、これからReactを学ぶ上での土台を作ることを目指します。

Webフロントエンドの役割とは

Webフロントエンドとは、ユーザーが直接目にして触れる部分のことです。ブラウザ上で動作し、ユーザーとのやり取りを担当します。

具体的には以下のような役割があります:

  • 情報の表示: サーバーから受け取ったデータを画面に表示する
  • ユーザー操作の受付: ボタンクリックや入力フォームなどのイベントを処理する
  • インタラクション: ユーザーの操作に応じて画面を動的に変化させる
  • UX(ユーザー体験)の提供: 快適で使いやすいインターフェースを実現する

昔のWebフロントエンド

2000年代のWebサイトは比較的シンプルでした。

<!-- 昔ながらのWebページ -->
<html>
  <body>
    <h1>商品一覧</h1>
    <div id="product-list">
      <!-- サーバー側で生成されたHTMLがそのまま表示される -->
    </div>
    <script>
      // jQueryで要素を操作
      $('#button').click(function() {
        $('#product-list').html('<p>読み込み中...</p>');
        // 新しいページをリクエストして全体をリロード
        location.href = '/products/new';
      });
    </script>
  </body>
</html>

この時代の課題:

  • ページ遷移のたびに画面全体がリロードされる(白い画面が一瞬表示される)
  • DOM操作が散らばり、コードの見通しが悪い
  • 画面の状態管理が難しく、バグが発生しやすい

Reactとは

Reactは、Facebookが2013年に公開したJavaScriptライブラリです。UIを構築するための革新的なアプローチを提供し、フロントエンド開発の世界を大きく変えました。

Reactが解決した問題

Reactが登場する前、複雑なWebアプリケーションを作るのは大変でした。

例えば、「いいねボタン」を実装する場合:

// jQuery時代の実装
$('#like-button').click(function() {
  const count = parseInt($('#like-count').text());
  $('#like-count').text(count + 1);
  $('#like-button').addClass('liked');
  // さらに他の場所の表示も更新...
  $('#header-like-count').text(count + 1);
  // 状態が色々な場所に散らばる
});

問題点:

  • 表示と処理が分離していない(HTMLとJSが密結合)
  • 同じデータを複数の場所で管理(バグの温床)
  • 変更の影響範囲が分かりにくい

Reactのアプローチ

Reactは「コンポーネント」という概念でこれを解決しました。

// Reactでの実装
function LikeButton() {
  const [count, setCount] = useState(0);
  const [liked, setLiked] = useState(false);
 
  const handleClick = () => {
    setCount(count + 1);
    setLiked(true);
  };
 
  return (
    <button
      className={liked ? 'liked' : ''}
      onClick={handleClick}
    >
      いいね {count}
    </button>
  );
}

特徴:

  • 見た目と処理が一箇所にまとまっている(コンポーネント)
  • 状態(state)が一箇所で管理されている
  • 宣言的に書ける(「どう変更するか」ではなく「どう見えるべきか」を書く)

モダンフロントエンドとは

Reactの登場以降、フロントエンド開発は「モダンフロントエンド」と呼ばれる新しい時代に入りました。

モダンフロントエンドの特徴

1. コンポーネント指向

UIを**再利用可能な部品(コンポーネント)**として構築します。

// ボタンコンポーネントを定義
function Button({ children, onClick }) {
  return <button onClick={onClick}>{children}</button>;
}
 
// 色々な場所で再利用
<Button onClick={handleSave}>保存</Button>
<Button onClick={handleDelete}>削除</Button>

2. 宣言的UI

どのように変更するか」ではなく、「どうあるべきか」を記述します。

// 宣言的:状態に応じてどう見えるべきかを記述
function UserStatus({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? <p>ログイン中</p> : <p>ログインしてください</p>}
    </div>
  );
}

従来の命令的な書き方だと:

// 命令的:DOMを直接操作して変更する
if (isLoggedIn) {
  document.getElementById('status').innerHTML = '<p>ログイン中</p>';
} else {
  document.getElementById('status').innerHTML = '<p>ログインしてください</p>';
}

3. 単一方向データフロー

データの流れが親から子へ一方向になり、データの追跡が容易になりました。

function App() {
  const [user, setUser] = useState(null);
 
  // データは親から子へ流れる
  return (
    <div>
      <Header user={user} />
      <Main user={user} />
    </div>
  );
}

仮想DOM:Reactの革新的な仕組み

Reactの最も革新的な概念の一つが**仮想DOM(Virtual DOM)**です。

DOM操作の問題

従来のJavaScriptでは、DOMを直接操作していました。しかしDOM操作は非常に重い処理です。

// DOMを直接操作(遅い)
for (let i = 0; i < 1000; i++) {
  const div = document.createElement('div');
  div.textContent = `Item ${i}`;
  document.body.appendChild(div); // 毎回再描画が走る
}

仮想DOMの仕組み

仮想DOMは、実際のDOMの軽量なコピーをJavaScriptのメモリ上に持ちます。

  1. 変更があったら仮想DOMを更新(軽い)
  2. 変更前と変更後の仮想DOMを比較(差分検出)
  3. 変更があった部分だけ実際のDOMに反映(最小限の操作)
function Counter() {
  const [count, setCount] = useState(0);
 
  // countが変わると、Reactは:
  // 1. 新しい仮想DOMツリーを作成
  // 2. 前回の仮想DOMと比較
  // 3. 変更があった<span>だけを実際のDOMで更新
  return (
    <div>
      <p>カウント: <span>{count}</span></p>
      <button onClick={() => setCount(count + 1)}>増やす</button>
    </div>
  );
}

仮想DOMのメリット

  • パフォーマンスの最適化: 必要最小限のDOM操作だけを実行
  • 開発者体験の向上: 開発者は最適化を気にせず、宣言的に書ける
  • クロスプラットフォーム: 同じ考え方でReact Native(モバイルアプリ)も実現

状態管理:アプリケーションの心臓部

もう一つの重要な概念が**状態管理(State Management)**です。

状態(State)とは

状態とは、アプリケーションが保持する動的なデータのことです。

例:

  • ログインしているユーザー情報
  • フォームの入力内容
  • モーダルの開閉状態
  • 取得したAPIのデータ

従来の問題点

jQuery時代は、状態が色々な場所に散らばっていました。

// グローバル変数で状態を管理(良くない例)
let currentUser = null;
let cartItems = [];
let isModalOpen = false;
 
// 色々な場所から直接変更される
function login(user) {
  currentUser = user;
  $('#username').text(user.name);
  $('#cart-count').text(cartItems.length);
}

問題:

  • どこで状態が変更されるか分からない
  • 状態の変更を追跡できない
  • バグの原因特定が困難

Reactの状態管理

Reactでは、状態はコンポーネント内に閉じ込められます

function ShoppingCart() {
  // この状態はこのコンポーネント内でのみ管理される
  const [items, setItems] = useState([]);
 
  const addItem = (item) => {
    // setItems関数を通してのみ変更できる
    setItems([...items, item]);
  };
 
  return (
    <div>
      <p>カート: {items.length}</p>
      <button onClick={() => addItem('商品')}>追加</button>
    </div>
  );
}

より大規模な状態管理

アプリケーションが大きくなると、複数のコンポーネント間で状態を共有する必要が出てきます。そこで登場したのが:

  • Context API: Reactに組み込まれている状態共有の仕組み
  • Redux: グローバルな状態管理ライブラリ(一時期デファクトスタンダード)
  • Recoil / Zustand / Jotai: より軽量でモダンな状態管理ライブラリ
// Context APIの例
const UserContext = createContext();
 
function App() {
  const [user, setUser] = useState(null);
 
  // 子孫コンポーネント全てでuserにアクセス可能
  return (
    <UserContext.Provider value={user}>
      <Header />
      <Main />
    </UserContext.Provider>
  );
}
 
function Header() {
  // どこからでも状態を取得できる
  const user = useContext(UserContext);
  return <div>ようこそ、{user?.name}さん</div>;
}

重要なのは:

  • 状態の変更が追跡可能
  • データの流れが明確
  • テストやデバッグがしやすい

まとめ

Reactとモダンフロントエンドが解決したこと:

  1. コンポーネント指向: UIを再利用可能な部品として構築
  2. 仮想DOM: 効率的なDOM操作でパフォーマンスを向上
  3. 宣言的UI: 「どうあるべきか」を記述することで可読性向上
  4. 状態管理: データの流れを明確にし、バグを減らす

これらの概念は、Reactだけでなく、Vue.jsやSvelteなど他のモダンフロントエンドフレームワークにも共通しています。

次回予告: 次の「ライフサイクル編」では、ReactコンポーネントのライフサイクルとuseEffectフックについて詳しく学びます。データ取得、イベントリスナーの登録、クリーンアップ処理など、実践的な内容を扱います!

参考リンク

ReactReact is the library for web and native user interfaces. Build user interfaces out of individual pieces called components written in JavaScript. React is designed to let you seamlessly combine components written by independent people, teams, and organizations.
favicon of https://react.dev/react.dev
ogp of https://react.dev/images/og-home.png
React の流儀 – ReactThe library for web and native user interfaces
favicon of https://ja.react.dev/learn/thinking-in-reactja.react.dev
ogp of https://ja.react.dev/images/og-learn.png

目次