Reactコンポーネントはpropsとstateの2種類を使ってデータを管理します。

それらを組み合わせることで、表示を変更したりイベントを発生させたりします。

propsとは

propsとは親コンポーネントから子コンポーネントに渡すことができる属性値です。

親コンポーネント内で使われている子コンポーネントに属性を設定することによって、propsとして子コンポーネントに値を渡せます。

またpropsは変更不可(イミュータブル)な値でないといけません。

<コンポーネント名 属性名=属性値 属性名=属性値 ... />

渡すことができる値

文字列、数値などJavaScriptで使えるデータ型であればなんでも渡すことができます。

属性値は{ }内に記述しますが、文字列に関しては" "で記述できます。

<User
  name="Taro" // 文字列
  age={15}  // 数値
  check={true}  // 真偽
  subject={['国語', '数学', '体育']}  // 配列
  body={{height: 164, weight: 58}}  // オブジェクト
  score={total(7, 4)}  // 関数
/>

propsの渡し方

import React from 'react';

// 親コンポーネントApp
const App = () => {
  return <Greeting name="Taro"/>
}

// 子コンポーネントGreeting
const Greeting = (props) => {
  return <div>Hi!{props.name}</div>
}

export default App;

// Hi!Taro

親コンポーネント(App)内の<Greeting />name="Taro"の属性を設定して、子コンポーネント(Greeting)に渡します。

propsは子コンポーネント(Greeting)の引数によって渡されるので、メソッドチェーンで必要な値を利用します。

stateとは

stateとはコンポーネントの内部で状態を管理する変数で、クラスコンポーネントでのみ利用可能になります。

またstateはpropsとは逆で変更可能(ミュータブル)な値になります。

stateの設定

stateはクラスコンポーネントのconstructorメソッド内でthis.stateにオブジェクト型で記述します。

class Counter extends React.Component {
  constructor() {
    super();
    this.state = { counter: 0 };
  }
}

stateの取得

【同コンポーネント内の場合】

this.state.key名で取得できます。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: 'Taro' };
  }

  render () {
    return <div>Hi!{this.state.name}</div>
  }
}

export default App;

// Hi!Taro

【子コンポーネントの場合】

propsで値を渡します。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: 'Taro' };
  }

  render () {
    return <Greeting name={this.state.name}/>
  }
}

const Greeting = (props) => {
  return <div>Hi!{props.name}</div>
}

export default App;

// Hi!Taro

<Greeting />の属性値にthis.state.nameを設定して、子コンポーネントのpropsで取得します。

setStateについて

stateの値を変更する場合、直接変更するのではなく、setStateを使って変更します。

setStateが実行されると、コールバックでrenderが実行されて再レンダリングが行われます。

setStateを使うときは関数にラップするのが一般的です。

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handlePlusButton = () => {
    this.setState({count: this.state.count + 1});
  }

  render() {
    return (
      <div>
        <div>count: { this.state.count }</div>
        <button onClick={this.handlePlusButton}>Click</button>
      </div>
    )
  }
}

export default Counter;
  1. Clickボタンを押すとthis.handlePlusButtonが実行されます。

  2. this.setStateでstateのcountを現在のカウント「0」に「+1」します。

  3. stateの値が「1」に変更され、renderが実行されて再レンダリングします。

子コンポーネントに関数を渡す

親コンポーネントで宣言した関数を子コンポーネントで実行したい場合は、propsの属性値に関数型で渡す必要があります。

関数型ではなく直接入れた場合、renderですぐ実行されてしまい、無限ループが起こってしまうので注意が必要です。

関数を実行ではなく登録するために関数型で記述しましょう。

// 親コンポーネント
parent = () => {
  // 実行内容
}

<コンポーネント名 child={() => parent()} />

// 子コンポーネント
<button onClick={() => child()}>ボタン</button>

【無限ループ例】

// 親コンポーネント
parent = () => {
  // 実行内容
}

<コンポーネント名 child={parent()} />

// 子コンポーネント
<button onClick={child()}>ボタン</button>

propsとstateを使ったカウントアプリ

最後のまとめとしてpropsとstateとsetStateを使って実装したアプリです。

コード

import React from 'react';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handlePlusButton = () => {
    console.log('click')
    this.setState({count: this.state.count + 1});
  }

  render() {
    return <CounterBox count={this.state.count} counterPlus={() => this.handlePlusButton()}/>
  }
}

const CounterBox = (props) => {
  return (
    <div>
      <div>counfsaast: { props.count }</div>
      <button onClick={()=> props.counterPlus()}>Click</button>
    </div>
  )
}

export default Counter;

まとめ

  • propsは親コンポーネントから子コンポーネントに渡せる属性値で、変更不可(イミュータブル)な値でないといけない。
  • stateはコンポーネントの内部で状態を管理する変数で、変更可能(ミュータブル)な値になる。
  • stateの値を変更するにはsetStateを使う。
  • 子コンポーネントに関数を渡す場合は、関数型で記述する。

さいごに

以上、propsとstateについてでした。

最初の頃はpropsとstateがゴチャゴチャになってしまうので、propsは属性でstateは状態ということを意識しながら慣れるまで実践あるのみです。

propsとstateはデータ管理において必須項目なのでマスターしたいところです。

参考