React・データを流しこむ

propsで値を渡す

同じ部品で違う中身を出すために、外から値を渡すのがpropsです。渡し方・受け取り方・分割代入・既定値・childrenまで、カードを3羽ぶん作りながら確認します。子から書きかえてはいけない理由も扱います。

前回、同じカードが3枚並びました。今回はここに1枚ずつ違う中身を入れます。

そのために外から渡す値がprops(プロパティ)です。コンポーネントは関数なので、propsはその引数にあたります。

// 渡す側(親)
<BirdCard name="シマエナガ" />

// 受け取る側(子)
function BirdCard(props) {
  return <h2>{props.name}</h2>
}

HTMLの属性を書く感覚で渡せますが、属性名は自分で決められます

渡し方——文字列以外は波かっこ

<BirdCard
  name="シマエナガ"        {/* 文字列はそのまま */}
  rare={3}                 {/* 数値は波かっこ */}
  isRare={true}            {/* 真偽値も波かっこ */}
  bird={birdObject}        {/* オブジェクトも波かっこ */}
/>

波かっこは「ここからJavaScriptです」の合図でした。rare="3"と書くと文字列の'3'になってしまい、rare >= 3のような比較が思ったとおりに動きません。

受け取り方——分割代入が定番

受け取る側は、引数として受けとります。

function BirdCard(props) {
  return (
    <div>
      <h2>{props.name}</h2>
      <p>{props.memo}</p>
    </div>
  )
}

props.が毎回付くのが読みにくいので、分割代入で取り出す書き方が定番です。

function BirdCard({ name, memo }) {
  return (
    <div>
      <h2>{name}</h2>
      <p>{memo}</p>
    </div>
  )
}

やっていることは同じです。引数の波かっこは「オブジェクトから取り出す」の合図でした。Reactの記事はほぼこの書き方なので、こちらに慣れておくと読むのが楽になります。

propsは読み取り専用

子の中でpropsを書きかえてはいけません。

function BirdCard({ name }) {
  name = 'スズメ'   // ✕ やってはいけない
  return <h2>{name}</h2>
}

理由は2つあります。

  • 画面が更新されない——Reactは「propsが書きかわった」を見ていません。表示は次に親が描き直したときの値に戻ります
  • 追えなくなる——値は親から流れてくるはずなのに、途中で勝手に変わると、どこで変わったのか探せなくなります

Reactではデータは上から下へ一方通行に流れます。この決まりのおかげで「この値はどこから来たのか」を親へさかのぼるだけで追えます。

children——タグで挟んだ中身

開始タグと終了タグで挟んだ中身は、childrenという決まった名前のpropsで受け取れます。

function Panel({ children }) {
  return <div className="rounded-2xl bg-white p-5 shadow-sm">{children}</div>
}
<Panel>
  <h2>シマエナガ</h2>
  <p>雪のようにまっ白な小鳥。</p>
</Panel>

枠だけ用意して、中身は使う側が決める」というときに便利です。カード・モーダル・レイアウトなど、入れ物系の部品でよく使います。

カードをpropsで書きかえる

BirdCardが4つの値を受け取るようにします。

function BirdCard({ name, emoji, area, memo }) {
  return (
    <div className="flex gap-4 rounded-2xl bg-white p-5 shadow-sm">
      <span className="text-4xl">{emoji}</span>
      <div>
        <div className="flex items-center gap-2">
          <h2 className="font-bold text-slate-800">{name}</h2>
          <span className="rounded-full bg-sky-100 px-2 py-0.5 text-xs text-sky-700">
            {area}
          </span>
        </div>
        <p className="mt-1 text-sm text-slate-600">{memo}</p>
      </div>
    </div>
  )
}

export default BirdCard

親からは、3羽ぶんの値を渡します。

<div className="mt-6 space-y-4">
  <BirdCard
    name="シマエナガ"
    emoji="🐦"
    area="北海道"
    memo="雪のようにまっ白な小鳥。ふわふわの丸い体。"
  />
  <BirdCard
    name="スズメ"
    emoji="🐤"
    area="まちなか"
    memo="いちばん身近な小鳥。ちゅんちゅん鳴いている。"
  />
  <BirdCard
    name="フクロウ"
    emoji="🦉"
    area="もり"
    memo="夜に活動する。首がぐるりとよく回る。"
  />
</div>

カードの見た目を直すときはBirdCard.jsxの1か所で済みます。3枚とも同時に変わります。これが部品にした効果です。

公式ドキュメントも見てみる

ja.react.dev外部サイトコンポーネントに props を渡す – React公式の「コンポーネントにpropsを渡す」。「propsを分割代入する」の節と、最後の「propsは時間とともに変化する」の節がこの回の要点そのものです

このレッスンのまとめ

  1. props=親から子へ渡す値。コンポーネントは関数なので、propsはその引数
  2. 文字列以外(数値・真偽値・オブジェクト)は波かっこで渡す
  3. 受け取りは分割代入{ name, memo }が定番。既定値も書ける
  4. propsは読み取り専用——子で書きかえない。変わる値はstateの担当
  5. タグで挟んだ中身はchildrenで受け取れる
  6. 渡す名前と受け取る名前がズレると、エラーなしで空欄になる

次は、この3枚をデータの配列から自動で並べます。8羽ぶんのカードを手で書かずに済ませる回です。

やってみよう:カードを3羽ぶんに書き分ける

BirdCardをpropsで受け取る形に変え、3羽ぶんを渡します。

  1. src/components/BirdCard.jsxの関数の引数を{ name, emoji, area, memo }にする
  2. 中の決め打ちの文字を、波かっこで受け取った値に差しかえる(すんでいる場所のチップも追加する)
  3. src/App.jsxの3つの<BirdCard />に、シマエナガ・スズメ・フクロウの値を渡す
水色の背景に、シマエナガ・スズメ・フクロウの3枚のカードが縦に並び、それぞれ違う絵文字・名前・すんでいる場所のチップ・説明が表示されている
同じ部品から、3羽ぶんの違うカードができました

3枚とも中身が違っていればOKです。カードの見た目を変えたくなったら、BirdCard.jsxだけ直せば3枚とも変わることも確かめてみてください。

よくある質問

propsとは何ですか?
親コンポーネントから子コンポーネントへ渡す値のことです。コンポーネントは関数なので、propsはその引数にあたります。渡された値をもとに、同じ部品で違う見た目を作れます。
propsを子コンポーネントの中で書きかえてもいいですか?
いけません。propsは読み取り専用です。書きかえても画面は更新されませんし、どこで値が変わったのか追えなくなります。変化する値が必要なときはstateを使います。
文字列以外も渡せますか?
渡せます。数値・真偽値・配列・オブジェクト・関数まで渡せます。文字列以外は波かっこで囲んで渡します(rare={3} のように)。
propsの名前に決まりはありますか?
自由ですが、渡す側と受け取る側で完全に一致させる必要があります。慣習として、値はそのままの名前(name・area)、関数はonから始める名前(onToggleFavorite)にすることが多いです。