React入門#5 〜stateの設定と取得と変更〜

## はじめに

タイトルについて記事にしました。
この記事で得る内容は以下の通りです。

・ stateの設定・取得・変更方法について

■ Reactに関する過去の記事はこちら
・ [React入門#1 〜Reactの基礎知識〜](https://qiita.com/s79ns/items/271ec50a26949e902016)
・ [React入門#2 〜JSXについて〜](https://qiita.com/s79ns/items/da61ddd58e0ac0d2baf6)
・ [React入門#3 〜create-react-appの環境構築〜](https://qiita.com/s79ns/items/69cc8e77994e90963a21)
・ [React入門#4 〜コンポーネント間でデータの受け渡しと再利用をする〜](https://qiita.com/s79ns/items/3dcc4a5c20b78dd09c9d)

## 状態(state)とは

・ コンポーネントで管理する変数のことです。
・ Reactのコンポーネントだけで使うことができる`state`を、<font color="red">Local state</font>といいます。
・ propsとして、親のコンポーネントから子コンポーネントに渡すことができます。

## なぜstateを使うのか

SPA開発時に、ページをリロードせず、JavaScriptでDOM操作をせずに表示を切り替えられるためです。

■ 注意点
・ render( )内で値を変更してはいけないというルールがあります。
・ 値を変更する時は、<font color="red">setstate( )</font>というメソッドを使って値を変更します。

■ なぜrender( )内で値を変更してはいけないのか
`state`の変更をすると、Virtual DOMを書き換える（再レンダー）処理が行われます。
再レンダーされたメソッドに値を変更する処理があると、`state`変更→再レンダーの無限ループが起きてしまいます。ですので、`setstate()`メソッドで`state`の変更を管理しています。

## stateの設定方法
・ <font color="red">Class Component</font>が前提条件となります。（<font color="green">Functional Component</font>は`state`を持つことができません）
・ `constructor()`メソッドの中で宣言し、オブジェクト型で記述します。

```react:src/Blog.jsx
class Blog extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isPublished: false
        }
    }
    // 中略
}
export default Blog;
```

## stateの取得
・ 同じコンポーネントの中なら、`this.state.key名`で取得することができます。
・ 子コンポーネントで参照したい場合は、`props`としてisPublishedの値を渡します。

```react:src/Blog.jsx
render() {
    return (
        <Article
            title="Reactの基礎知識"
            isPublished={this.state.isPublished}
        />
    );
}
```

## stateの変更
・ `setstate()`メソッドを使います。
・ 関数にラップするのが一般的です。

例えば、togglePublishedという関数を作り、その中で`setState()`メソッドを使う感じです。
下の例では、`setState()`メソッドの中で、オブジェクト型を表す波括弧をつけて、isPublishedの真偽値を!で反転させています。

```react:src/Blog.jsx
togglePublished = () => {
    this.setState({
        isPublished: !this.state.Published
    })
};
```

## 例

例えば、自身が運営するブログで、Reactの使い方というタイトルの記事を公開するかどうか切り替えるページがあったとします。

![reactの使い方.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/67ce2efd-677b-2b1c-27ba-9e9915b2e874.png)

```react:Blog.jsx
import React from "react";
import Article from "./Article";

class Blog extends React.Component {
  constructor(props) {
    super(props);

    // Articleの公開状態を変更する為のstateで、初期状態は'false'で非公開の状態にします
    this.state = {
      isPublished: false,
    };
  }

  render() {
    return (
      <>
        // isPublishedという変数名で子コンポーネントに引き渡す✳︎中身は上のconstructorを参照している状態
        <Article title={"Reactの使い方"} isPublished={this.state.isPublished} />
      </>
    );
  }
}
```

チェック状態が`checked={props.isPublished}`の値になっているので、公開状態のチェックボックスをクリックしても変わリません。

```react:Article.jsx
import React from "react";

const Article = (props) => {
  return (
    <div>
      <h2>{props.title}</h2>
      <label htmlFor="check">公開状態：</label>
      <input type="checkbox" checked={props.isPublished} />
    </div>
  );
};

export default Article;
```

そこで公開状態を反転させる関数を作りますが、この関数は子コンポーネントでは参照できないので、引き渡す形をとります。

```react:Blog.jsx
  // 公開状態を反転させる関数
  togglePublished = () => {
    this.setState({
      isPublished: !this.state.isPublished,
    });
  };
```

toggleという`props`にして、関数型で渡します。（toggleとして渡した時に、this.togglePublishedを呼び出します。）
こうする事で、再レンダーが起きて、無限ループしてしまうのを防ぎます。

```react:Blog.jsx
<Article title={"Reactの使い方"} isPublished={this.state.isPublished} toggle={() => this.togglePublished()} />
```

こちらも、無限ループを防ぐ為、クリック後に関数型として`props.toggle`を呼び出します。

```react:Article.jsx
<input type="checkbox" checked={props.isPublished} id="check" onClick={() => props.toggle()} />
```

これでチェックボックスをクリックすると、チェックが切り替わる様になります。

![react.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/ae3576b6-d764-163d-b8f5-8ee248592c7f.gif)

## エラー例

関数型以外で記述してみます。

```react:Article.jsx
<input type="checkbox" checked={props.isPublished} id="check" onClick={props.toggle()} />
```

無限ループしてしまいますよ！と怒られてしまいます。

![無限ループするぞ！.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/b64aea9d-9cbf-777a-5bbb-940320705a1b.png)