React未経験なので公式チュートリアルから学んでみる Part4（propsについて理解する）

## はじめに
前回まではJSXの書き方や、JavaScriptとJSXの併用の仕方など、少しReactっぽさがない学習が続いていましたが、今回からReactの基礎的な概念について触れていきます。

今回はpropsについて学びます。

前回は[こちら](https://qiita.com/course_k/items/ed4d2c15854b03a98de6)
初回は[こちら](https://qiita.com/course_k/items/4df3f0a1bfb8f36da55f)

## propsとは
### 概要
propsとは親コンポーネントから、子コンポーネントに値をやりとりするために使うものです。
ただの値だけではなく、オブジェクトや配列、関数なども渡すことができます。
実際に確認してみましょう。
### コンポーネントの確認
概要で触れたコンポーネントの親子関係がどのようなものであるかについて確認します。
ファイルを２つ作成します。
（ファイル作成については初回の[こちら](https://qiita.com/course_k/items/4df3f0a1bfb8f36da55f#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E5%88%A9%E7%94%A8)を参考にしてください）

「Parent.js」と「Child.js」の2つを作成しています。
<img width='40%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/5cebae23-d1d2-8062-e2a5-be7ca5bfbae6.png'>

`Child.js`では入力欄を用意します。
exportしないとコンポーネントとして利用できないので、exportするのを忘れないようにします。
```react:Child.js
function Child() {
    return (
        <>
            <label>入力欄</label>
            <input type='text' placeholder='入力してください' />
        </>
    );
}

export default Child;
```
`Parent.js`では`Child.js`をインポートして、`Child`コンポーネントとして利用します。
このとき、`Child`コンポーネントは`Parent`コンポーネントの子要素となるわけです。

```react:Parent.js
import Child from './Child.js';

function Parent() {
    return (
        <>
            <h3>Child出力1つ目</h3>
            <Child />
            <h3>Child出力2つ目</h3>
            <Child />
        </>
    );
}

export default Parent;
```

次に`App.js`で`Parent.js`をインポートして、`Parent`コンポーネントとして利用します。
```react:App.js
import logo from './logo.svg';
import './App.css';
import Parent from './Parent.js';

function App() {
  return (
    <>
      <h1>Parentの出力</h1>
      <Parent />
    </>
  );
}

export default App;
```

最終的な画面表示は以下のようになるはずです。
<img width='60%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/e62d5651-614b-6309-94a7-2b66bf730a51.png'>
入力欄を子コンポーネントへ分割しているので、同じ部品を何度も使い回すことができます。

ここで、「入力欄」の文言を動的に変更したいとなった場合、どうすれば良いでしょうか。
例えば、1つ目の入力欄は「氏名」、2つ目は「電話番号」としたい時、それぞれでコンポーネントを用意するのは面倒です。
そこで役に立つのがpropsです。

### propsの基本
propsは親コンポーネントから子コンポーネントへ値などをやりとりする際に使われます。
propsを使うためには、親コンポーネントのファイル、子コンポーネントのファイルのそれぞれに修正を加える必要があります。
#### 親コンポーネントの設定
まず、親コンポーネントのファイルから修正します。

```react:Parent.js
import Child from './Child.js';

function Parent() {
    return (
        <>
            <h3>Child出力1つ目</h3>
            <Child title='氏名' />
            <h3>Child出力2つ目</h3>
            <Child title='電話番号' />
        </>
    );
}

export default Parent;
```
`<Child>`タグに`title`を設定し、1つ目は氏名、2つ目は電話番号としておきます。

この時のポイントは、
・`title`と文字列をイコールで繋ぐこと
・文字列をシングルクォート、またはダブルクォートで囲んでおくこと
の2つです。

要は、オブジェクトのキーとバリューと同じイメージです。
※オブジェクトの場合はキーとバリューを`:`(コロン)で繋ぎます

ここで設定したpropsは、子コンポーネントへオブジェクトの形で受け渡されます。

#### 子コンポーネントの設定
次にChildコンポーネントのファイルを編集しましょう。
```react:Child.js
function Child(props) {
    return (
        <>
            <label>{props.title}</label>
            <input type='text' placeholder='入力してください' />
        </>
    );
}
```
Child関数に引数を設定します。この時の名前はなんでもよいのですが、ここでは`props`としておきます。
次に、`<label>`タグの中身を`{props.title}`に書きかえます。
[前回](https://qiita.com/course_k/items/ed4d2c15854b03a98de6#jsx%E5%86%85%E3%81%AB%E3%81%84%E3%82%8D%E3%81%84%E3%82%8D%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B)の記事で確認しましたが、`{}`内はJavaScriptの記述を書くことができます。

親コンポーネントで設定したpropsはオブジェクトとして渡ってくるため、`オブジェクト.キー名`の形で、親コンポーネントで設定した値を取得できます。

画面は次のように表示されます。
<img width='60%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/b61fa0a1-826a-f3ab-fac6-f07f2d35ccab.png'>
1つ目が氏名、2つ目が電話番号となっていることがわかります。

このように、親から子に、値を引数のようにして受け渡すことで、子コンポーネントを動的に変更することができます。

新しく「住所」という入力欄を作りたい場合、子コンポーネントのソースを修正することなく、親コンポーネントからpropsとして「住所」を引き渡すことで、新しい要素を追加できるのです。


## propsをいろいろ試してみる
propsの使い方の基本がわかったところで、いろいろなことを試してみます。

### 複数の値を渡す
入力欄のタイトルだけではなく、「入力してください」と初期表示される内容も分けてみましょう。

まずは親コンポーネントを修正します。
```react:Parent.js(関数のみ抜粋)
function Parent() {
    return (
        <>
            <h3>Child出力1つ目</h3>
            <Child title='氏名' defaultVal='React 太郎' />
            <h3>Child出力2つ目</h3>
            <Child title='電話番号' defaultVal='090-0000-0000' />
        </>
    );
}
```
新たに`defaultVal`を追加しています。

次に、子コンポーネントを修正します。
```react:Child.js(関数のみ抜粋)
function Child(props) {
    return (
        <>
            <label>{props.title}</label>
            <input type='text' placeholder={props.defaultVal} />
        </>
    );
}

```
placeholder属性に`{props.defaultVal}`を設定します。

別々の値が初期表示されるようになりました。
<img width='60%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/ac3b8140-9b79-f30e-8aef-024028b9214c.png'>

propsを複数渡したい場合は、渡したい分だけ親コンポーネントに記載すれば、そのまま子コンポーネントで使用することができます。

### propsの受け取り、受け渡し
ここからはReactというよりもJavaScriptよりの話になります。
（React独自の書き方ではなく、JavaScriptにもともとある記法の話です。）

propsはオブジェクトとして親から子に引き渡されるので、次のような形で受け取ったり、受け渡したりできます。

#### 分割代入を使う
分割代入とは、オブジェクトや配列の中身をいっぺんに取り出して変数へ代入する方法です。
```javascript:Example.js
let obj = {
    person: 'Taro',
    age: 28,
    country: 'Japan'
};
let { person, age, country } = obj;

// 人名:Taro、年齢:28、国:Japan
console.log(`人名:${person}、年齢:${age}、国:${country}`);
```
このように書くことで`obj`の中身がそれぞれの変数へ格納されます。
この分割代入を利用して、以下のようにpropsを受け取ることができます。
```react:Child.js(関数のみ抜粋)
function Child({ title, defaultVal }) {
    return (
        <>
            <label>{title}</label>
            <input type='text' placeholder={defaultVal} />
        </>
    );
}
```
引数部分の`props`を分割代入で受け取る形、`{ title, defaultVal }`に変更しました。
これで、親コンポーネントから受け渡されている2つの値が、それぞれ`title`、`defaultVal`に格納されます。
そして、`<label>`タグの中身、`placeholder`の中身にそれぞれの変数を設定しています。

分割代入を使うと、いちいち`オブジェクト.キー名`として値を取り出す必要がないので、スッキリ書くことができます。
#### デフォルト引数を使う
JavaScriptの関数では、引数にデフォルト値を設定することができます。
```javascript:Example.js
function print(person = 'nanashi', age = 99) {
    console.log(`人名:${person}、年齢:${age}`);
}
// 人名:Taro、年齢:28
print('Taro', 28);
// 人名:nanashi、年齢:99
print();
```
このように、引数が設定されなかったときのために初期値を設定しておくことができます。

まず、子コンポーネントから以下のように設定します。
```react:Child.js(関数のみ抜粋)
function Child({ title = '入力欄', defaultVal = '入力してください' }) {
    return (
        <>
            <label>{title}</label>
            <input type='text' placeholder={defaultVal} />
        </>
    );
}
```
分割代入を使用しつつ、デフォルト引数を設定しています。

次に、親コンポーネントでpropsを渡さないコンポーネントを追加しましょう。
```react:Parent.js(関数のみ抜粋)
function Parent() {
    return (
        <>
            <h3>Child出力1つ目</h3>
            <Child title='氏名' defaultVal='React 太郎' />
            <h3>Child出力2つ目</h3>
            <Child title='電話番号' defaultVal='090-0000-0000' />
            <h3>Child出力3つ目</h3>
            <Child />
        </>
    );
}
```
結果は以下のようになります。
<img width='60%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/42d4378a-d45f-25db-4fb4-7259f95ab82a.png'>
３つ目の`<Child>`タグにはpropsを渡していませんが、画面上は子コンポーネント側で設定した初期値が表示されています。
このようにして、万が一propsが渡されなかった場合でも対応ができます。

#### スプレッド構文を使う
スプレッド構文とは、配列やオブジェクトを一気に展開して受け渡す方法です。
```javascript:Example.js
let obj = {
    person: 'Taro',
    age: 28,
    country: 'Japan'
}

function fn({ person, age, country }) {
    console.log(`人名:${person}、年齢:${age}、国:${country}`);
}

// 人名:Taro、年齢:28、国:Japan
fn({ ...obj });
```
配列やオブジェクトの前に`...`をつけることで、その中身をすべて展開して渡すことができます。

子コンポーネントは先ほどのものを流用できるので、親コンポーネントについて修正を加えます。
```react:Parent.js(関数のみ抜粋)
function Parent() {
    let nameObj = {
        title: '氏名',
        defaultVal: 'React 太郎'
    }
    return (
        <>
            <h3>Child出力1つ目</h3>
            {/* titleだけ渡す */}
            <Child {...nameObj} />
            <h3>Child出力2つ目</h3>
            {/* defaultValだけ渡す */}
            <Child title='電話番号' defaultVal='090-0000-0000' />
        </>
    );
}
```
出力の1つ目に、定義したオブジェクトをスプレッド構文で渡しています。
1つずつpropsを列記せずともいっぺんに渡すことができるので、スッキリと書くことができます。

画面は以下のように出力されます。
<img width='60%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/399c184e-4aee-9dc5-9333-ca2fe222c643.png'>


このように、分割代入やデフォルト引数、スプレッド構文をうまく使いこなすことで、より便利にReactを書くことができます。

## 特別なprops
子コンポーネントにおいて、propsを受け取る際の変数名は基本的に自由ですが、名前が指定されているpropsがあります。それが`children`です。

この`children`は、コンポーネントがネストされている場合にネストの内側（子要素）を受け取ります。

どういうことか実際に確認してみましょう。

まずは子コンポーネントを編集します。
```react:Child.js(関数のみ抜粋)
function Child({ children }) {
    return (
        <>
            <div style={{
                border: "solid 3px red",
                width: "300px",
                padding: "10px"
            }}>
                {children}
            </div >
        </>
    );
}
```
引数に`children`を設定します。
そして、`<div>`タグの中に`children`を記載しておき、`<div>`タグには赤枠線のスタイルを設定します。

次に親コンポーネントを編集しましょう。
```react:Parent.js
function Parent() {
    return (
        <>
            <h3>Child出力1つ目</h3>
            <Child>
                <div>1つ目のChildタグの子要素</div>
                <button>click me!</button>
            </Child>

            <h3>Child出力2つ目</h3>
            <Child>
                <div>2つ目のChildタグの子要素</div>
                <input type='radio' id='label1' name='fruits' value='apple' />
                <label for='label1'>りんご</label>
                <input type='radio' id='label2' name='fruits' value='banana' />
                <label for='label2'>バナナ</label>
                <input type='radio' id='label3' name='fruits' value='チェリー' />
                <label for='label3'>さくらんぼ</label>
            </Child >
        </>
    );
}
```
`<Child>`タグの中に、それぞれ違う要素をネストさせています。

なお、今までの例では
`<Child>...</Child>`ではなく
`<Child />`と記載していましたが、これはネストさせる要素がなかったためです。

`<Child>`でもよさそうに思いますが、Reactにおいては閉じタグがない場合でも必ず明示的にタグを閉じる必要があるため、末尾に`/`を記載しています。
（Reactにおける閉じタグについては、第2回記事の[こちら](https://qiita.com/course_k/items/c901e9859941e25311fe#2-%E5%BF%85%E3%81%9A%E3%82%BF%E3%82%B0%E3%81%AF%E9%96%89%E3%81%98%E3%82%8B)を参照）

表示結果を確認します。
<img width='60%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/586968b7-8370-5f37-44ca-e5fc06e02c5e.png'>
Child出力1つ目、2つ目ともに、親コンポーネントで設定した`<Child>`タグ内のネストされた要素が、赤枠で囲まれています。
この赤枠は子コンポーネントで指定しているものです。

つまり、`children`を使うことで、子コンポーネントでは外側の枠のみ定義しておき、中身については親コンポーネントから自由に渡すことが可能になります。

## まとめ
`props`を使って、親から子に値を受け渡す方法を確認しました。
今回は文字列しか確認していませんが、数値や真偽値、オブジェクト、関数なども受け渡すことができます。
また、ネストした要素を受け渡すための`children`についても学びました。

これら2つをうまく使うことで、コンポーネントそれぞれを独立させることができます。
親コンポーネントから渡すpropsをいくら変えたところで、子コンポーネントへの影響はありません。
こうすることで変更に強いソースコードとすることができます。

次回は画面を描画する際の分岐や繰り返しについて学びます。
~~Part5はこちら~~
（次回の記事は鋭意作成中です。）

## 参考にしたサイト
* [REACTを学ぶ-コンポーネントに props を渡す](https://ja.react.dev/learn/passing-props-to-a-component)
* [【2023年最新】React(v18)完全入門ガイド｜Hooks、Next.js、Redux、TypeScript](https://www.udemy.com/course/react-complete-guide/)