たった5分で分かる！Reactで親子コンポーネントのデータの受け渡す方法

#1.はじめに
この記事ではReactで親子関係にあるコンポーネントのデータの受け渡し方法を紹介します

Reactでのコンポーネント間のデータの受け渡しっていざ使おうというときに忘れてしまいがちですよね。
なのでこの記事では誰でも扱えるように細かいステップに分けてまとめました。

次の3つの順番で紹介します。

**1. なぜコンポーネント間で受け渡しをするのか？**
**2. 親から子に値を渡す方法**
**3. 子から親に値を渡す方法**

この記事を読めばコンポーネント間のデータの受け渡しが誰でも簡単にできるようになります。

#2.なぜコンポーネント間でデータを受け渡しするのか？
なぜコンポーネント間で受け渡しをするのでしょうか？
その理由は**データのスコープを小さくできるため**です。

Reduxを使えばデータを一元管理できるので親子で受け渡しをしなくても、どのコンポーネントからも呼び出すことができます。

しかし、全ての値を一元管理してしまうと影響範囲が大きく、どこで値が変更されているのかが見えづらいです。
そのため長期的に運用するにはスコープを小さくするのは必須なことが分かりますよね。


#3.親から子へのデータの受け渡し
ここからはコンポーネント間で受け渡しをするにはどうすれば良いのかを解説していきます。
まずは親から子にデータを渡す方法です。

親から子にデータを渡すのは主に2つの方法があります

**1. 属性で渡す方法**
**2. タグの中身で渡す方法**


##3-1.属性でのデータの受け渡し
1つ目の受け渡し方法は親の属性に値を指定して受け渡す方法です。
次の2ステップで作ることができます。

**1. 親に「属性名=値」で渡したい値を指定**
**2. 子では「this.props.属性名」で受取り**

親から受け取った値を子で強調して表示するプログラムのコードを例に挙げます。

<img width="159" alt="親から子.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621361/d3180147-69cb-5917-cc4a-72ea30a57119.jpeg">


```javascript:属性での値の受け渡し
//親コンポーネント
class Parent extends React.Component {
  render() {
    return <Child title="Qiita"></Child>
  }
}

//子コンポーネント
class Child extends React.Component {
  render() {
    return <div>入力した文字は<b>{this.props.title}</b>です！</div>;
  }
}

React.render(<Parent />, document.getElementById('app'));
```

最初のステップでは親コンポーネントで属性名を指定します。
今回の例では「title="Qiita"」でtitle属性に「Qiita」の文字列を渡していますね。

次のステップでは子で受け取った属性を「this.props.title」で表示しています。
this.propsには親コンポーネントから受け取った値が入っているのが肝です。

##3-2.タグの中身の受け渡し
2つ目の方法は親のタグの中身に渡したいDOMを指定し、子に渡します。
ポイントとなるのは子コンポーネントの「this.props.children」で受け取れるところです。

1. 親のタグの中身に渡したいDOMを指定
2. 子では「**this.props.children**」で受取り

```javascript:タグの中身での受け渡し
//親コンポーネント
class Parent extends React.Component {
  render() {
    return <Child><b>Qiita</b></Child>
  }
}

//子コンポーネント
class Child extends React.Component {
  render() {
    return <div>入力した文字は{this.props.children}です！</div>;
  }
}

React.render(<Parent />, document.getElementById('app'));
```

親のコンポーネントではタグの中身の「&lt;b&gt;Qiita&lt;/b&gt;」を渡し、
子コンポーネントの「this.props.children」で渡した値を表示しています。

##3-3.親から子への受け渡しの使い分け
親から子に値の受け渡しは、属性で渡す方法とタグの中身を渡す方法の2種類紹介しました。
この2つの方法は次の通りに使い分けます。

- **JavaScriptの値を渡したい→props.属性名**
- **DOMを渡したい→props.children**

属性で渡す場合は文字列だけでなく、数値型やメソッドなど色んな型を渡すことができます。
そのためJavaScriptオブジェクトを渡したいときに適しています。

一方、タグの中身を渡す場合は階層構造で表せれるのでDOMを渡したいときに適しています。

#4.子から親へのデータの受け渡し
子から親への受け渡しは少し複雑ですが次の3ステップで実装できます。

**1. コンストラクタでステートの初期化**
**2. 親から子にメソッドを渡し、子でメソッドを呼び出す**
**3. 親のステートを設定するメソッドを用意**

次の例はボタンを押すたびにカウントアップするプログラムです。

![子から親への受け渡し.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621361/7329df42-f096-9150-a3b1-e61ff2624e3d.gif)


```javascript:子から親の値の受け渡し
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 0};
    this.ParentAddCount = this.ParentAddCount.bind(this)
  }
  
  //カウントアップ
  ParentAddCount() {
    let count = this.state.count + 1;
    this.setState({count:count});
  }
  
  render() {
    return (
      <div>
        <Child onCountUp={this.ParentAddCount}></Child>
        <div>{this.state.count}回押しました。</div>
      </div>);
  }
}

//子コンポーネント
class Child extends React.Component {
  render() {
    return <button onClick={this.props.onCountUp}>加算</button>
  }
}

React.render(<Parent />, document.getElementById('app'));
```

##4-1.コンストラクタでステートを初期化
親コンポーネントが作成されたときにステートを初期化します。
ステートはコンポーネントが持っている状態で、クラスで例えるとメンバー変数みたいなものです。

##4-2.親から子にメソッドを渡し、子でメソッドを呼び出す
親コンポーネントのonCountUp属性を使って子コンポーネントにParentAddCountメソッドを引き渡しています。
前章の「親から子に属性を渡す」で解説した方法です。

そして、親から受けとったメソッドをクリックしたときに呼び出すためにonClickで「onCountUp」をキーに呼び出しています。

##4-3.親のステートを設定するメソッドを用意
最後に子から受け取ったイベントの通知が来たときに親で処理したいメソッドを定義します。

ParentAddCountではcountを1つ上げてsetStateメソッドでセットしています。
このときにsetStateメソッドを使わず、**stateを直接編集してボタンを押しても画面には反映されない**です。
なぜならsetStateメソッドでReactにステートを更新したことを通知しているためです。

```javascript:画面に反映されない例
  //カウントアップ
  ParentAddCount() {
    let count = this.state.count + 1;
    this.state= {count:count};   //画面には反映されない
  }

```

#5.まとめ
この記事では親子関係にあるコンポーネントのデータの受け渡しを解説しました。

**・スコープを小さくしたいためにコンポーネント間の受け渡しを行う**
**・親から子に渡したいときは属性またはタグの中身を使う**
**・子から親に渡したいときは親から受け取ったメソッドを使う**