第1回

なぜReactなのか:コンポーネント思考と宣言的UIを理解する

HTMLのコピペ地獄からコンポーネント思考へ。jQueryとReactの違い、宣言的UIとは何かを対話形式でゼロから解説。

·12分で読める
たける
たける Reactって結局、HTMLとJavaScriptで書けることをわざわざ難しくしてるだけじゃないですか?
りこ
りこ 実際に手を動かして確認してみましょう。まず、登場人物紹介ページをHTMLで作ることを想像してみて。キャラクターが5人いるとして、どう書く?
たける
たける カードのHTMLを5回書く……あ、コピペして名前や説明文を変えていく感じですかね。
りこ
りこ そう。そしてカードのデザインを変えたくなったら?
たける
たける 5箇所全部直す……

HTMLで書くとこうなる

5人分のキャラクターカードを素のHTMLで書くとこうなる。

<!-- index.html -->
<div class="character-card">
  <img src="/characters/riko.jpg" alt="大沢りこ">
  <h2>大沢りこ</h2>
  <p>フロントエンドチームリーダー</p>
  <p>13年のエンジニア歴を持つ。...</p>
</div>

<div class="character-card">
  <img src="/characters/takeru.jpg" alt="宮本たける">
  <h2>宮本たける</h2>
  <p>インターン</p>
  <p>元商社マン。...</p>
</div>

<!-- あと3人分、同じ構造が続く -->

これでも動く。でも、3つの問題がある。

  1. 修正が大変:カードのHTMLを変えたら全員分直す必要がある
  2. 追加が大変:6人目が増えたら、また同じHTMLを書く
  3. データとUIが混ざっている:「りこのプロフィール」と「カードの見た目」が同じ場所にある

Reactで書くとこうなる

Reactでは「カードの形」と「カードの中身(データ)」を分離できる。

// カードの「形」を1回だけ定義する
const CharacterCard = ({ name, role, image, bio }) => (
  <div className="character-card">
    <img src={image} alt={name} />
    <h2>{name}</h2>
    <p>{role}</p>
    <p>{bio}</p>
  </div>
)

// データを配列で持つ
const characters = [
  { id: 'riko', name: '大沢りこ', role: 'フロントエンドチームリーダー', image: '/characters/riko.jpg', bio: '...' },
  { id: 'takeru', name: '宮本たける', role: 'インターン', image: '/characters/takeru.jpg', bio: '...' },
  // ...
]

// 配列をループして全員分を表示
const CharactersPage = () => (
  <div>
    {characters.map(c => (
      <CharacterCard key={c.id} {...c} />
    ))}
  </div>
)
たける
たける カードを1回書いて、あとはデータで制御するってことですね。カードのデザインを変えたら全員に反映されるし、人を追加するにはデータを1行追加するだけ。
りこ
りこ それがコンポーネント思考。「繰り返す形」を部品にして、データを差し込む。

コンポーネントとは何か

コンポーネントとは、UIの部品のこと。

CharacterCard というコンポーネントは「キャラクターを1人分表示する方法」を知っている。誰を表示するかは、渡されるデータ(props)で変わる。

このサイト全体もコンポーネントの組み合わせでできている。

App
├── Header(ナビゲーション)
├── CharactersPage(登場人物ページ)
│   ├── RosterCard × 5(ロスター選択)
│   └── CharacterCard(詳細カード)
│       ├── 画像エリア
│       └── プロフィールエリア
└── Footer

それぞれの部品が独立していて、別の場所でも使い回せる。

jQueryとの違い

「jQueryでも同じことができるじゃないか」という疑問が出るかもしれない。違いはUIの更新の考え方にある。

jQueryの場合:「どう変えるか」を命令する

// クリックしたら、この要素のテキストを変えろ
$('#count').text(count + 1);
// この要素を表示しろ
$('#modal').show();
// このリストに要素を追加しろ
$('#list').append('<li>' + item + '</li>');

画面をどう操作するかを1ステップずつ命令する。UIが複雑になると、どこで何を変えたか追うのが難しくなる。

Reactの場合:「何を表示するか」を宣言する

// countが何であれ、常にこのUIを表示する
return <p>クリック回数: {count}</p>

// isOpenの値によって、常にこう表示する
return isOpen ? <Modal /> : null

// itemsの中身が何であれ、常にこうマッピングする
return items.map(item => <li key={item.id}>{item.name}</li>)

「今の状態(state)に基づいて、こういうUIを表示する」と宣言するだけ。状態が変わったらReactが差分を計算して、変わった部分だけ自動で更新する。

たける
たける jQueryは「これをこう変えろ」、Reactは「こういう状態のときはこう見せる」ってことですよね。
りこ
りこ 正確。だからReactは「宣言的UI」と呼ばれる。UIが複雑になるほど、この考え方の差が効いてくる。
たける
たける 登場人物ページで画像をクリックしたら別の画像に切り替わるやつ、Reactだとどう書くんですか?
りこ
りこ 「選択中の画像番号」をstateで持って、それに応じて表示する画像を変えるだけ。第9回でやる。今はまず環境を作ろう。

まとめ

  • コンポーネント:UIの部品。1回定義して、データを変えながら何度でも使い回す
  • props:コンポーネントに渡すデータ。コンポーネントの外から「中身」を差し込む
  • 宣言的UI:「今の状態ではこう見える」を定義する。どう変えるかはReactに任せる
  • 画面が複雑になるほど、コンポーネント思考と宣言的UIの恩恵が大きくなる

次の第2回では、開発環境を整える。Node.jsのインストールから、ブラウザでコードの変更がリアルタイムに反映されるまでをやる。