1. ホーム
  2. React

【React】props でコンポーネントに値を渡す方法|親から子へのデータの受け渡しを解説

Share

React でアプリを作っていくと、画面を小さな部品(コンポーネント)に分け、それらを組み合わせて全体を作るようになります。そのとき欠かせないのが props です。props は、親コンポーネントから子コンポーネントへ値を渡すためのしくみで、関数に引数を渡す感覚でデータを受け渡せます。この記事では、props の基本の渡し方・受け取り方から、文字列以外の値の渡し方、children、デフォルト値、そして初心者がつまずきやすい「props は書き換えられない」というルールまで、順を追って解説します。

props とは何か

props(プロパティの略)は、親コンポーネントから子コンポーネントへ値を渡すためのしくみです。関数を呼び出すときに引数を渡すのとよく似ています。関数が引数を受け取って処理を変えるように、コンポーネントも props を受け取って表示する内容を変えられます。

たとえば「あいさつを表示する」コンポーネントを1つ作っておけば、渡す名前を変えるだけで「Taro さん向け」「Hanako さん向け」と、いくつも作り分けられます。同じ見た目・同じ動きの部品を、中身の値だけ変えて使い回せるのが props の役割です。データは常に親(上)から子(下)へという一方向に流れます。

基本の渡し方と受け取り方

まずは一番シンプルな例を見てみましょう。親コンポーネントは、子コンポーネントを書くときに 属性名="値" の形で値を渡します。HTML のタグに属性を書く感覚です。子コンポーネント側は、関数の第1引数として props オブジェクトを受け取り、props.属性名 で値を取り出します。

Greeting.jsx
// 子コンポーネント:props を受け取って表示する
function Greeting(props) {
  return <p>こんにちは、{props.name}さん</p>;
}

// 親コンポーネント:name に値を渡して使う
function App() {
  return (
    <div>
      <Greeting name="Taro" />
      <Greeting name="Hanako" />
    </div>
  );
}

export default App;

親が <Greeting name="Taro" /> と書いて渡した値は、子の Greeting では props.name で受け取れます。この例では「こんにちは、Taroさん」「こんにちは、Hanakoさん」と、渡した名前に応じて2種類のあいさつが表示されます。props は複数渡すこともでき、その場合は props.nameprops.age のように属性ごとに取り出します。

分割代入でスッキリ受け取る

props.nameprops.age と毎回 props. を書くのは少し冗長です。実務では、引数の部分で分割代入を使い、必要な値を直接取り出す書き方が一般的です。

UserCard.jsx
// 引数の { } の中で、使いたい props を直接受け取る
function UserCard({ name, age }) {
  return (
    <div>
      <p>名前: {name}</p>
      <p>年齢: {age}</p>
    </div>
  );
}

// 使うとき
// <UserCard name="Taro" age={20} />

function UserCard({ name, age }) のように書くと、props オブジェクトから nameage が取り出され、そのまま変数として使えます。props. を省けるうえ、そのコンポーネントがどんな値を受け取るのかが関数の先頭で一目で分かるので、読みやすくなります。この記事でも、以降は分割代入で書いていきます。

文字列以外の値を渡す

ここまでは文字列を渡してきました。props には数値・真偽値・配列・オブジェクト・関数など、あらゆる値を渡せます。ただし渡し方にルールがあります。文字列を渡すときだけダブルクオートで囲めばよく、それ以外の値は必ず { }(波かっこ)で囲んで渡します{ } の中は JavaScript の式として評価されるためです。

App.jsx
function App() {
  const hobbies = ['読書', '映画'];
  const profile = { city: '東京', job: 'エンジニア' };

  return (
    <ProfileCard
      name="Taro"          // 文字列はダブルクオートでOK
      age={20}             // 数値は { } で囲む
      isAdmin={true}       // 真偽値も { }
      hobbies={hobbies}    // 配列も { }
      profile={profile}    // オブジェクトも { }
    />
  );
}

よくある間違いが、数値を age="20" と書いてしまうことです。これだと文字列の "20" が渡ってしまい、計算などで思わぬ結果になります。数値として渡したいときは age={20}{ } で囲みます。受け取る側は、値の種類にかかわらず同じように分割代入で取り出せます。

ProfileCard.jsx
function ProfileCard({ name, age, isAdmin, hobbies, profile }) {
  return (
    <div>
      <p>{name}({age}歳)</p>
      {isAdmin && <p>管理者です</p>}
      <p>趣味: {hobbies.join('、')}</p>
      <p>住まい: {profile.city}</p>
    </div>
  );
}

渡された値の型はそのまま保たれます。配列なら hobbies.join('、') のように配列メソッドが使え、オブジェクトなら profile.city のようにプロパティにアクセスできます。isAdmin のような真偽値は、{isAdmin && ...} の形で「true のときだけ表示する」といった条件分岐に使えます。

タグの間の内容を children で受け取る

コンポーネントを開始タグと終了タグで囲み、その間に書いた内容を子コンポーネントに渡すこともできます。これは props.children という特別な props で受け取ります。カードや枠など、「外側の見た目は共通で、中身だけ差し替えたい」ときに便利です。

Card.jsx
// children で「タグの間の内容」を受け取る
function Card({ children }) {
  return <div className="card">{children}</div>;
}

function App() {
  return (
    <Card>
      <h2>お知らせ</h2>
      <p>今日は晴れです。</p>
    </Card>
  );
}

<Card></Card> の間に書いた <h2><p> が、そのまま children として Card に渡され、<div className="card"> の中に表示されます。children は名前が固定されている点だけ注意すれば、通常の props と同じように扱えます。

props にデフォルト値を設定する

親が値を渡さなかったとき、propsundefined になります。渡されなかった場合に使う初期値を決めておきたいときは、分割代入のデフォルト値を使うのが簡単です。= の後ろに初期値を書きます。

Button.jsx
// label が渡されなければ '送信' を使う
function Button({ label = '送信' }) {
  return <button>{label}</button>;
}

// <Button />              → 「送信」ボタン
// <Button label="保存" />  → 「保存」ボタン

{ label = '送信' } と書いておくと、親が label を渡さなかったときだけ '送信' が使われます。渡したときはその値が優先されます。よく使う値をデフォルトにしておくと、呼び出す側のコードが短くなり、書き忘れによる不具合も防げます。

子コンポーネントで props を書き換えてはいけない

props を使ううえで、初心者が特につまずきやすいのが「props は読み取り専用」というルールです。子コンポーネントは、受け取った props読むことはできても、書き換えてはいけません。次のようなコードは避けてください。

Counter.jsx
// ❌ 子で props を直接書き換えてはいけない
function Counter({ count }) {
  count = count + 1; // これはやってはいけない
  return <p>{count}</p>;
}

なぜダメなのでしょうか。React では、データは親から子への一方向に流れます。props はあくまで親が持っているデータの「コピーの表示」であり、子が勝手に書き換えると、親の状態と表示がずれて画面の動きが予測できなくなります。オブジェクトや配列の props についても同じで、props 経由で受け取ったオブジェクトの中身を書き換えるのも避けます。

では、値を変化させたいときはどうすればよいのでしょうか。答えは「データを持っている親側で変更する」です。値の変更は、その値を管理している親コンポーネントの useState などで行い、更新後の値をあらためて props として子に渡します。子は渡された最新の値を表示するだけ、という役割分担にすると、動きが追いやすく安定したコードになります。

親の関数を props として渡す

「子で値を変えたいときは親側で変更する」と説明しました。とはいえ、ボタンは子コンポーネントにあることも多いはずです。そんなときは、親が持っている関数を props として子に渡し、子のボタンからその関数を呼び出します。これがイベント処理を親子でやり取りする定番のパターンです。

App.jsx
import { useState } from 'react';

// 子:ボタンが押されたら、渡された関数を呼ぶだけ
function AddButton({ onAdd }) {
  return <button onClick={onAdd}>+1</button>;
}

// 親:state と、それを更新する関数を持つ
function App() {
  const [count, setCount] = useState(0);

  const handleAdd = () => {
    setCount(prev => prev + 1);
  };

  return (
    <div>
      <p>カウント: {count}</p>
      {/* 関数を props として渡す */}
      <AddButton onAdd={handleAdd} />
    </div>
  );
}

export default App;

親の Appcount という状態と、それを増やす handleAdd 関数を持っています。この関数を onAdd という props で子の AddButton に渡し、子はボタンがクリックされたら onAdd を呼び出すだけです。ボタンを押すと親の handleAdd が実行され、親の状態が更新されて再描画されます。値は親から子へ、イベント(変更の合図)は子から親へという流れが、React でのデータのやり取りの基本形です。

まとめ

props は、親コンポーネントから子コンポーネントへ値を渡すためのしくみで、関数の引数のように働きます。親は <Greeting name="Taro" /> のように渡し、子は function Greeting(props) または分割代入の function Greeting({ name }) で受け取ります。文字列以外の数値・真偽値・配列・オブジェクト・関数は { } で囲んで渡し、開閉タグの間の内容は props.children で受け取れます。渡されなかったときの初期値は分割代入のデフォルト値で設定できます。そして最も大切なのが、props は読み取り専用で子では書き換えないこと、データは親から子へ一方向に流れるということです。値を変えたいときは親側で変更し、必要なら親の関数を props として渡して子から呼び出します。この流れをつかめば、コンポーネントを組み合わせた React アプリづくりがぐっと分かりやすくなります。

参考ページ