React hooksとclassコンポーネントにおけるsetStateの挙動の違いについて(動かせるコードあり)

# 概要

こちらは以下の記事に書いたhooksとclassコンポーネントにおけるsetStateの違いを別記事にしたものです．
https://qiita.com/yseki_/items/71511db1a60ab22ee663

## 忙しい人向けまとめ
hooksとクラス型コンポーネントのsetStateでは挙動が違う
hooksでは古いステートが引き継がれないため，更新の際は**古いステートもセットする必要がある**．

## それぞれのステート更新について

まずはhooksとclassのsetStateの違いを体験してみてください．
以下二つをhtmlファイルに貼り付け，お好きなブラウザで開いてみてください．
うまく動作しない場合，以下のリポジトリをcloneしてファイルをブラウザに貼り付けてください．
https://github.com/YutaSeki36/reactSetStateDiff

### クラス型コンポーネント

```classComponent.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>ClassComponent</title>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
​
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
​
<script type="text/babel">
class ClassComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
a: 0,
b: 0
};
​
this.handleChangeA = this.handleChangeA.bind(this);
}
​
handleChangeA(a) {
this.setState({ a: this.state.a + a });
}
​
render() {
console.log(`a: ${this.state.a}, b: ${this.state.b}`);
return (
<div>
<p>a: {this.state.a}</p>
<p>b: {this.state.b}</p>
​
<button onClick={() => this.handleChangeA(1)}>a+1</button>
</div>
);
}
}
​
ReactDOM.render(<ClassComponent />, document.getElementById("root"));
</script>
</body>
</html>
```

### 関数型コンポーネント

```FunctionComponent.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>FuntionComponent</title>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
​
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
​
<script type="text/babel">
const FuncComponent = props => {
const [state, setState] = React.useState({ a: 0, b: 0 });
​
const handleChangeA = a => {
setState({ a: state.a + a });
};
​
console.log(`a: ${state.a}, b: ${state.b}`);
​
return (
<div>
<p>a: {state.a}</p>
<p>b: {state.b}</p>
​
<button onClick={() => handleChangeA(1)}>a+1</button>
</div>
);
};
​
ReactDOM.render(<FuncComponent />, document.getElementById("root"));
</script>
</body>
</html>
```

## 検証

それぞれ見た目は以下のようになるかと思います．

<img width="152" alt="スクリーンショット 2020-01-20 20.25.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214145/9d390fc3-8816-0abd-c9aa-f8510014f1f4.png">

まずはクラス型コンポーネントの `a+1` を押してみましょう．
<img width="552" alt="スクリーンショット 2020-01-20 20.27.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214145/8cbbc15f-891b-7024-9aeb-ef95bb498fd4.png">

このように，無事更新ができました．


次は関数型コンポーネントで動作確認を行なってみましょう．

<img width="271" alt="スクリーンショット 2020-01-20 20.29.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214145/e3a130e4-7316-9d44-b6f7-287db2392bea.png">

このように，hooksでステートの更新を行うと，bがundefinedになってしまいました．

## 解決策

[公式チュートリアル](https://ja.reactjs.org/docs/hooks-state.html#tip-using-multiple-state-variables)に，以下のような記述があります．

>しかしクラスでの this.setState とは異なり、state 変数の更新は、マージではなく必ず古い値を置換します。

とありますので，hooksによるステート更新の際は古いステートもセットする必要があります．

先ほどの関数型コンポーネントファイルのステート更新mesoddo部分を以下のように書き換えます．

```funcCom.html
const handleChangeA = a => {
 // スプレッド構文を用いて、古いステートも記述する
          setState({ ...state, a: state.a + a });
};
```

これで無事にステート更新を行うことができました．
<img width="297" alt="スクリーンショット 2020-01-20 20.38.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214145/8de690d9-0f2f-a293-118e-e9a9bfd15594.png">


## 結び

あまりReactに慣れていない状態でhooksに手を出してしまい，初歩的なところで躓いてしまいました．
しっかりと公式ドキュメントにも書いている内容だったため，今後新たな技術を学ぶ際は公式ドキュメントに目を通そうと思いました．

(誤字脱字，間違った内容などあればコメントください🙇‍♂️)