初めてのコンポーネント

コンポーネントは、React における最重要コンセプトのひとつです。皆さんがユーザインターフェース (UI) を構築するときの基盤となるものですので、React の旅路はコンポーネントから始めていくことにしましょう!

このページで学ぶこと

  • コンポーネントとは何か
  • React アプリでコンポーネントが果たす役割
  • 初めてのコンポーネントの書き方

コンポーネント:UI の構成部品

Web の世界では、HTML で <h1><li> といった組み込みタグを使い、リッチで構造化されたドキュメントを作成することができます。

<article>
<h1>My First Component</h1>
<ol>
<li>Components: UI Building Blocks</li>
<li>Defining a Component</li>
<li>Using a Component</li>
</ol>
</article>

このマークアップは、記事自身 (<article>)、見出し (<h1>)、そして番号付きリスト (<ol>) による目次(一部省略しています)を表現しています。我々がウェブで目にするサイドバー、アバター、モーダル、ドロップダウンといったあらゆる UI パーツの裏側では、このようなマークアップが、スタイルのための CSS やユーザ対話のための JavaScript と組み合わさりながら働いています。

React では、あなたのマークアップと CSS と JavaScript を、独自の “コンポーネント” と呼ばれる、アプリのための再利用可能な UI 要素にまとめることができます。上記にある目次のためのコードを、<TableOfContents /> と呼ばれるコンポーネントにすることができるのです。その裏では、やはり <articles><h1> といった同じ HTML タグを使っています。

HTML タグを使う時と同様にして、コンポーネントを組み合わせたり、並び替えたり、ネストしたりして、ページ全体をデザインすることができます。例えばあなたが今読んでいるこのページも、以下のような React コンポーネントから作られています。

<PageLayout>
<NavigationHeader>
<SearchBar />
<Link to="/docs">Docs</Link>
</NavigationHeader>
<Sidebar />
<PageContent>
<TableOfContents />
<DocumentationText />
</PageContent>
</PageLayout>

プロジェクトが成長するとともに、設計・デザインのいろいろな部分を、既に書いたコンポーネントを再利用することで構築できるようになり、開発速度がアップすることに気付くでしょう。上記のような目次を、<TableOfContents /> を書くことでどのページにでも加えることができるのです! Chakra UIMaterial UI のような、React オープンソースコミュニティーで共有されている何千ものコンポーネントを使い、プロジェクトを一気にスタートさせることも可能です。

コンポーネントの定義

伝統的なウェブページの作成方法とは、ウェブ開発者が先にコンテンツをマークアップしてから、ユーザとのインタラクションを加えるために JavaScript をちょっと添える、というものでした。これはウェブにとってインタラクションが「あると嬉しい」レベルのものだった時代にはうまく機能していました。しかし今や、インタラクションはほぼすべてのサイトとあらゆるアプリで必要とされるものです。React は同じテクノロジを使っていますが、インタラクティビティ・ファーストになっています。すなわち React コンポーネントとは、マークアップを添えることができる JavaScript 関数です。コンポーネントは以下のような見た目をしています(以下のコードは編集できます)。

export default function Profile() {
  return (
    <img
      src="https://i.imgur.com/MK3eW3Am.jpg"
      alt="Katherine Johnson"
    />
  )
}

コンポーネントは以下のようにして作成します。

Step 1: コンポーネントをエクスポートする

頭にある export default標準的な JavaScript の構文です(React 特有のものではありません)。これでファイル内のメインの関数をマークし、後で他のファイルからそれをインポートできるようにします。(コンポーネントのインポートとエクスポートに詳細があります!)

Step 2: 関数を定義する

function Profile() { } のように書くことで、Profile という名前の JavaScript 関数を定義します。

落とし穴

React コンポーネントは普通の JavaScript 関数ですが、名前は大文字から始める必要があります。さもないと動作しません!

Step 3: マークアップを加える

このコンポーネントは srcalt という属性を有する <img /> タグを返しています。<img /> はまるで HTML のように書かれていますが、裏では実際には JavaScript です! この構文は JSX と呼ばれるもので、これによりマークアップを JavaScript 内に埋め込めるようになります。

return 文は、以下のように 1 行にまとめて書いても構いません。

return <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />;

しかし return キーワードと同じ行にマークアップ全体が収まらない場合は、括弧で囲んで以下のようにする必要があります。

return (
<div>
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
</div>
);

落とし穴

括弧がないと、return の後にあるコードはすべて無視されてしまいます

コンポーネントを使う

Profile コンポーネントが定義できたので、それをほかのコンポーネント内にネストさせることができます。例えば Profile コンポーネントを複数回使う Gallery というコンポーネントをエクスポートできます。

function Profile() {
  return (
    <img
      src="https://i.imgur.com/MK3eW3As.jpg"
      alt="Katherine Johnson"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}

ブラウザに見えるもの

大文字・小文字の違いに気をつけてください。

  • <section> は小文字なので、React はこれが HTML タグを指しているのだと理解します。
  • <Profile /> は大文字の P で始まっているので、React は Profile という名前の独自コンポーネントを使いたいのだと理解します。

Profile の中には <img /> という HTML が更に含まれてます。最終的に、ブラウザに見えるのは以下のようなものです。

<section>
<h1>Amazing scientists</h1>
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
</section>

コンポーネントのネストと整理方法

コンポーネントは普通の JavaScript 関数ですので、同じファイルに複数のコンポーネントを書いておくこともできます。これはコンポーネントが比較的小さい場合や互いに密接に関連している場合には便利です。ファイルの中身が増えてきたら、いつでも Profile を別のファイルに移動できます。このやり方についてはすぐ後で、インポートについてのページで学びます。

Profile コンポーネントは Gallery コンポーネントの中でレンダーされています(しかも何回も)ので、Gallery親コンポーネントであり、Profile を「子」としてレンダーしている、と言うことができます。これが React の魔法です。一度コンポーネントを定義したら、それをどこにでも何回でも好きなだけ使えるということです。

落とし穴

コンポーネントがほかのコンポーネントをレンダーすることはできますが、コンポーネントの定義をネストさせてはいけません

export default function Gallery() {
// 🔴 Never define a component inside another component!
function Profile() {
// ...
}
// ...
}

上記のコードはとても遅く、バグの原因になります。代わりに、すべてのコンポーネントをトップレベルで定義するようにしてください。

export default function Gallery() {
// ...
}

// ✅ Declare components at the top level
function Profile() {
// ...
}

子コンポーネントが親コンポーネントの情報を必要とする場合は、コンポーネント定義をネストさせるのではなく props を通じて渡すようにしてください。

さらに深く知る

隅から隅までコンポーネント

React アプリケーションは “ルート (root)” コンポーネントから始まります。通常、これは新しいプロジェクトを開始したときに自動的に作成されます。例えば CodeSandbox を使う場合や、Next.js のようなフレームワークを使う場合、ルートコンポーネントは pages/index.js に定義されています。ここまでの例でも、ルートコンポーネントをエクスポートしていたわけです。

ほとんどの React アプリでは隅から隅までコンポーネントが使われます。つまり、ボタンのような再利用可能なところでのみ使うのではなく、サイドバーやリスト、最終的にはページ本体といった大きなパーツのためにも使うのです。コンポーネントは、1 回しか使わないような UI コードやマークアップであっても、それらを整理するための有用な手段です。

Next.js のようなフレームワークではこれを更に 1 歩押し進めます。空の HTML ファイルから始めて JavaScript で React にページ内容の管理を引き継がせるのではなく、あなたの書いた React コンポーネントから HTML ファイル自体も自動生成するのです。これにより、JavaScript コードがロードされる前にコンテンツの一部をアプリが表示できるようになります。

その一方で、多くのウェブサイトでは React を “対話機能をちょっと添える” ためにのみ使っています。そのようなサイトはページ全体のためのルートコンポーネントを 1 つだけ持つのではなく、たくさんのルートコンポーネントを持っています。必要しだいで、React を使う量は多くても少なくても構わないのです!

まとめ

これで初めての React 体験は完了です。キーポイントをいくつかおさらいしておきましょう。

  • React によりアプリのための再利用可能な部品であるコンポーネントを作成できる。

  • React アプリでは UI のあらゆる部品はコンポーネントである。

  • React のコンポーネントとは普通の JavaScript 関数だが、以下の点が異なる。

    1. 名前は常に大文字で始まる。
    2. JSX マークアップを return する。

チャレンジ 1/4:
コンポーネントのエクスポート

このサンドボックスはルートコンポーネントがエクスポートされていないため動作しません:

function Profile() {
  return (
    <img
      src="https://i.imgur.com/lICfvbD.jpg"
      alt="Aklilu Lemma"
    />
  );
}

答えを見る前に自分で修正してみましょう!