UI の記述
React は、ユーザインターフェース(UI)を表示するための JavaScript ライブラリです。UI はボタンやテキスト、画像といった小さな要素から構成されています。React ではこれらを、ネストして再利用できるコンポーネントにまとめることができます。ウェブサイトであれ携帯電話アプリであれ、画面上のすべてのものはコンポーネントに分解することができます。この章では、React コンポーネントを作成し、カスタマイズし、条件付きで表示する方法について学びます。
この章で学ぶこと
初めてのコンポーネント
React アプリケーションはコンポーネントと呼ばれる独立した UI のパーツで構成されています。React コンポーネントとは、マークアップを添えることができる JavaScript 関数です。コンポーネントは、ボタンのような小さなものであることもあれば、ページ全体といった大きなものであることもあります。以下は、3 つの 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> ); }
コンポーネントのインポートとエクスポート
1 つのファイルに多くのコンポーネントを宣言することもできますが、大きなファイルは取り回しが難しくなります。これを解決するために、コンポーネントを個別のファイルにエクスポートし、別のファイルからそのコンポーネントをインポートすることができます。
import Profile from './Profile.js'; export default function Gallery() { return ( <section> <h1>Amazing scientists</h1> <Profile /> <Profile /> <Profile /> </section> ); }
JSX でマークアップを記述する
各 React コンポーネントは、ブラウザにレンダーされるマークアップを含んだ JavaScript 関数です。React コンポーネントは、マークアップを表現するために JSX という拡張構文を使用します。JSX は HTML によく似ていますが、少し構文が厳密であり、動的な情報を表示することができます。
既存の HTML マークアップを React コンポーネントに貼り付けても、常にうまく機能するわけではありません。
export default function TodoList() { return ( // This doesn't quite work! <h1>Hedy Lamarr's Todos</h1> <img src="https://i.imgur.com/yXOvdOSs.jpg" alt="Hedy Lamarr" class="photo" > <ul> <li>Invent new traffic lights <li>Rehearse a movie scene <li>Improve spectrum technology </ul>
このような既存の HTML がある場合は、コンバータを使って修正することができます。
export default function TodoList() { return ( <> <h1>Hedy Lamarr's Todos</h1> <img src="https://i.imgur.com/yXOvdOSs.jpg" alt="Hedy Lamarr" className="photo" /> <ul> <li>Invent new traffic lights</li> <li>Rehearse a movie scene</li> <li>Improve spectrum technology</li> </ul> </> ); }
JSX に波括弧で JavaScript を含める
JSX を使うことで、JavaScript ファイル内に HTML のようなマークアップを記述し、レンダーのロジックとコンテンツを同じ場所に配置することができます。時には、そのマークアップ内でちょっとした JavaScript ロジックを追加したり、動的なプロパティを参照したりしたいことがあります。このような状況では、JSX 内で波括弧を使い JavaScript への「窓を開ける」ことができます。
const person = { name: 'Gregorio Y. Zara', theme: { backgroundColor: 'black', color: 'pink' } }; export default function TodoList() { return ( <div style={person.theme}> <h1>{person.name}'s Todos</h1> <img className="avatar" src="https://i.imgur.com/7vQD0fPs.jpg" alt="Gregorio Y. Zara" /> <ul> <li>Improve the videophone</li> <li>Prepare aeronautics lectures</li> <li>Work on the alcohol-fuelled engine</li> </ul> </div> ); }
Ready to learn this topic?
JSX に波括弧で JavaScript を含めるを読んで、JSX 内から JavaScript のデータにアクセスする方法を学びましょう。
Read Moreコンポーネントに props を渡す
React コンポーネントでは、props を使ってお互いに情報をやり取りします。親コンポーネントは、子コンポーネントに props を与えることで、情報を渡すことができます。HTML の属性 (attribute) と似ていますが、オブジェクト、配列、関数、そして JSX まで、どのような JavaScript の値でも渡すことができます!
import { getImageUrl } from './utils.js' export default function Profile() { return ( <Card> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> </Card> ); } function Avatar({ person, size }) { return ( <img className="avatar" src={getImageUrl(person)} alt={person.name} width={size} height={size} /> ); } function Card({ children }) { return ( <div className="card"> {children} </div> ); }
条件付きレンダー
コンポーネントは、さまざまな条件によって表示内容を切り替える必要がよくあります。React では、JavaScript の if
文、&&
や ? :
演算子などの構文を使って、条件付きで JSX をレンダーすることができます。
この例では、JavaScript の &&
演算子を使い、チェックマークを条件付きでレンダーしています。
function Item({ name, isPacked }) { return ( <li className="item"> {name} {isPacked && '✔'} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }
リストのレンダー
データの集まりから複数のよく似たコンポーネントを表示したいことがよくあります。React で JavaScript の filter()
や map()
を使って、データの配列をフィルタリングしたり、コンポーネントの配列に変換したりすることができます。
配列内の各要素には、key
を指定する必要があります。通常、データベースの ID を key
として使うことになるでしょう。key は、リストが変更されても各アイテムのリスト内の位置を React が追跡できるようにするために必要です。
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return ( <article> <h1>Scientists</h1> <ul>{listItems}</ul> </article> ); }
コンポーネントを純粋に保つ
いくつかの JavaScript の関数は純関数です。純関数には以下の特徴があります。
- 自分の仕事に集中する。呼び出される前に存在していたオブジェクトや変数を変更しない。
- 同じ入力には同じ出力。同じ入力を与えると、純関数は常に同じ結果を返す。
コンポーネントを常に厳密に純関数として書くことで、コードベースが成長するにつれて起きがちな、あらゆる種類の不可解なバグ、予測不可能な挙動を回避することができます。以下は純粋ではないコンポーネントの例です。
let guest = 0; function Cup() { // Bad: changing a preexisting variable! guest = guest + 1; return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup /> <Cup /> <Cup /> </> ); }
このコンポーネントを純粋にするには、既に存在する変数を書き換えるのではなく、prop を渡すようにすることができます。
function Cup({ guest }) { return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup guest={1} /> <Cup guest={2} /> <Cup guest={3} /> </> ); }
UI をツリーとして理解する
React はコンポーネント間あるいはモジュール間の関係性をモデル化するために、ツリー構造を使用します。
React レンダーツリーとはコンポーネントの親子関係を表現したものです。
ツリーの上側、つまりルートに近いコンポーネントはトップレベルコンポーネントです。子を持たないコンポーネントはリーフ(葉)コンポーネントです。このようなコンポーネントの分類は、データの流れやレンダーパフォーマンスを理解する際に有用です。
アプリを理解する上では、JavaScript のモジュール間の関係性をモデルすることも重要です。このようなものをモジュール依存関係ツリーと呼びます。
依存関係ツリーは、関連する JavaScript コードをすべてバンドルしてクライアントがダウンロード・レンダーできるようにするために、ビルドツールでよく使用されます。バンドルサイズが大きいと、React アプリのユーザ体験は悪化します。モジュール依存関係ツリーを理解することは、そのような問題をデバッグするのに役立ちます。
Ready to learn this topic?
UI をツリーとして理解するを読んで、レンダーツリーやモジュール依存関係ツリーの作り方、そしてそのような考え方がユーザ体験やパフォーマンスを改善する際にどのように役立つのかについて学びましょう。
Read More次のステップ
初めてのコンポーネントに進んで、この章をページごとに読み進めましょう!
もしくは、すでにこれらのトピックに詳しい場合、インタラクティビティの追加について読んでみましょう。