【第3回】React初心者入門!Props(プロップス)を使ってパーツを使い回そう

javascript-react-3 プログラミング

前回は、ヘッダーやプロフィールカードなどのコンポーネント自作とCSS装飾に挑戦しました。

しかし、前回のコードには1つ大きな課題がありました。 それは、「プロフィールカードに書かれた名前やテキストが固定(直書き)されている」 ということです。これだと、他の人のプロフィールカードを作りたい時に、同じようなファイルを何個も作らなければならなくなってしまいます。

そこで登場するのが、Reactの超重要機能 「Props(プロップス)」 です。

今回は、前回作った App.jsx に手を加えながら、Propsの仕組みと使い方をマスターしていきましょう!

1. Props(プロップス)とは?

Props(Propertiesの略)を一言でいうと、「親のコンポーネントから、子のコンポーネントへデータを渡すための仕掛け」 です。

HTMLのタグを書くときに <img src=”photo.jpg” width=”100″ /> のように属性を指定しますよね? ReactのPropsもまったく同じ感覚で使えます。

  • これまでのカード: 内容が決め打ちされた「完成品の置物」
  • Propsを使ったカード: データを入れると見た目が変わる「たい焼きの型」

Propsを使えば、1つのコンポーネント(型)を用意しておくだけで、データ(中身)を変えて何個でもパーツを使い回せる ようになります。

2. 実際にやってみよう!ProfileCardをProps対応にする

まずは、前回作成した src/ProfileCard.jsx を開いて、外部からデータを受け取れるように改造してみましょう。

改造前(第2回のコード)

文字が直接書かれています。

function ProfileCard() {
  return (
    <div className="profile-card">
      <div className="avatar">🚀</div>
      <h2>React 開発者</h2>
      <p>フロントエンド開発を勉強中のエンジニアです!</p>
    </div>
  )
}

改造後(Propsを使ったコード)

関数の引数で props を受け取り、波カッコ { } を使って画面に埋め込みます!

function ProfileCard(props) {
  return (
    <div className="profile-card">
      <div className="avatar">{props.avatar}</div>
      <h2>{props.name}</h2>
      <p>{props.bio}</p>
    </div>
  )
}

export default ProfileCard

💡 ポイント

  • function ProfileCard(props) のように引数で props(オブジェクト)を受け取ります。
  • JSXの中で {props.name} のように書くと、渡されたデータ(文字列など)を埋め込むことができます。

3. 親(App.jsx)からデータを渡してカードを量産する

受け取る側の準備ができたので、今度は呼出元である src/App.jsx からデータを渡してみましょう。

src/App.jsx を以下のように書き換えます。

import Header from './Header'
import ProfileCard from './ProfileCard'
import CounterButton from './CounterButton'
import './App.css'

function App() {
  return (
    <div className="app-container">
      <Header />

      <main className="main-content">
        {/* Propsを使って、カードごとに違うデータを渡す! */}
        <ProfileCard
          avatar="🚀"
          name="React A"
          bio="フロントエンド開発を勉強中のエンジニアです!"
        />

        <ProfileCard
          avatar="🎨"
          name="デザイン B"
          bio="UI/UXデザインが得意です。最近CSSアニメーションにハマっています。"
        />

        <ProfileCard
          avatar="⚽"
          name="スポーツ C"
          bio="休日はサッカーと筋トレ!Web開発でスポーツアプリを作りたいです。"
        />

        <CounterButton />
      </main>
    </div>
  )
}

export default App

ブラウザを確認してみてください。 ProfileCard.jsx というファイルは1つしか作っていないのに、全く違う内容のカードが3つ並んだはずです! これぞコンポーネント再利用の醍醐味です。

4. プロの書き方:「分割代入」でスッキリ書こう!

実は、先ほどの props.name や props.bio と毎回 props. を書くスタイルは、実際の開発現場ではあまり使われません。

JavaScriptの 「分割代入(Destructuring)」 という機能を使うと、もっと直感的でスッキリ書くことができます。

ProfileCard.jsx を以下のように書き直してみましょう!

function ProfileCard({ avatar, name, bio }) {
  return (
    <div className="profile-card">
      <div className="avatar">{avatar}</div>
      <h2>{name}</h2>
      <p>{bio}</p>
    </div>
  )
}

export default ProfileCard

引数の部分を ({ avatar, name, bio }) と括ることで、props. を省略して直接 {name} や {bio} と書けるようになりました。

5. 【応用】配列(map)を使ってスマートに並べる

map() は、JavaScriptの「配列(リスト)」に備わっている便利な命令(メソッド)です。

一言でいうと、「元の配列に入っているデータを1つずつ取り出し、加工して、新しい配列を作る」 というものです。

🍳 たとえば「料理」で例えると…

  • 元の配列(材料): ['りんご', 'いちご', 'バナナ']
  • 加工の命令: 「ジュースにする(〇〇ジュース)」
  • map() の結果: ['りんごジュース', 'いちごジュース', 'バナナジュース']

元の材料(配列)は壊さずに、全要素に同じ処理を適用した新しいリスト を作ってくれるのが map() です。

map()の普通のJavaScriptでの基本構文

まずはReactを離れて、純粋なJavaScriptのコードで動きを見てみましょう。

const numbers = [1, 2, 3];

// 配列の数字をすべて2倍にする
const doubled = numbers.map((num) => {
  return num * 2;
});

console.log(doubled); // 👉 [2, 4, 6] が出力される!

コードの分解解説

  1. numbers.map(…)numbers という配列の要素を1つずつ取り出して処理してね」と命じています。
  2. (num) => { … }取り出された1つのデータが入る「仮の入れ物(引数)」です。名前は item でも x でも好きに付けてOKです。
    • 1回目:num に 1 が入る ➔ 1 * 2(2)を返す
    • 2回目:num に 2 が入る ➔ 2 * 2(4)を返す
    • 3回目:num に 3 が入る ➔ 3 * 2(6)を返す
  3. return加工した後の「完成品」を返します。この返ってきた値が新しい配列の要素になります。

なぜ React で map() が必須なの?

Reactでは、「データの配列」を「画面(JSX)のリスト」に変換する ときに map() を使います。

「データ(文字や数字)」を map() の工場に入れると、「HTMLタグで包まれたコンポーネント」 になって出てくるイメージです。

超重要!Reactの key 属性ってとは?

Reactで map() を使うと、コンソール画面にこんな警告(エラーメッセージ)が出ることがあります。

⚠️ Warning: Each child in a list should have a unique “key” prop.

これは、「リストの各パーツに、識別用の目印(key)をつけて」 というReactからのメッセージです。

なぜ key が必要なのか?

Reactは、画面の「変更があった場所だけ」をシュッと一瞬で書き換えるのが得意なライブラリです。

もしリストの途中に新しいカードが1枚挿入されたり削除されたりした時、key(名前シールやID)が付いていないと、Reactはどれが入れ替わったのか見失ってしまい、リスト全体を作り直す羽目になります。

// ⭕ 正しい書き方(一意のIDを key に指定する)
{members.map((member) => (
  <ProfileCard key={member.id} name={member.name} />
))}
  • key に渡すもの: データベースのIDなど、「絶対に他と被らない一意の値(文字列や数値)」 を渡します。
  • NGな書き方: key={index}(map の第2引数で取れる配列の順番)をセットするのは、並び替えや削除でバグの原因になるため、原則非推奨です。

map()を使ってコードをすっきりさせよう

では今までのプロフィールカードを3つ並べるコードを、src/App.jsx をさらにスマートに進化させてみましょう。

import Header from './Header'
import ProfileCard from './ProfileCard'
import CounterButton from './CounterButton'
import './App.css'

function App() {
  // メンバー情報のデータ配列
  const members = [
    {
      id: 1,
      avatar: '🚀',
      name: 'React a',
      bio: 'フロントエンド開発を勉強中のエンジニアです!',
    },
    {
      id: 2,
      avatar: '🎨',
      name: 'デザイン b',
      bio: 'UI/UXデザインが得意です。最近CSSアニメーションにハマっています。',
    },
    {
      id: 3,
      avatar: '⚽',
      name: 'スポーツ c',
      bio: '休日はサッカーと筋トレ!Web開発でスポーツアプリを作りたいです。',
    },
  ]

  return (
    <div className="app-container">
      <Header />

      <main className="main-content">
        {/* mapを使って配列データから自動でカードを生成する */}
        {members.map((member) => (
          <ProfileCard
            key={member.id}
            avatar={member.avatar}
            name={member.name}
            bio={member.bio}
          />
        ))}

        <CounterButton />
      </main>
    </div>
  )
}

export default App

⚠️ 注意点:key 属性を忘れずに!

6. まとめ&次回予告

お疲れ様でした!今回はReact開発で必須となるPropsの基本をマスターしました。

  • Propsとは: 親コンポーネントから子コンポーネントへデータを渡す仕組み
  • 再利用性: 1つのコンポーネント(型)に異なるPropsを渡せば、いくつでもパーツを使い回せる
  • 配列と map(): データ配列を使えば、繰り返し描画もスマートに書ける

次回は、ユーザーがテキストボックスに入力した文字をリアルタイムに画面へ反映させる 「フォーム入力と状態管理(useState)」 について解説したいと思います。

コメント