概要
こちらは以下の記事に書いたhooksとclassコンポーネントにおけるsetStateの違いを別記事にしたものです.
https://qiita.com/yseki_/items/71511db1a60ab22ee663
忙しい人向けまとめ
hooksとクラス型コンポーネントのsetStateでは挙動が違う
hooksでは古いステートが引き継がれないため,更新の際は古いステートもセットする必要がある.
それぞれのステート更新について
まずはhooksとclassのsetStateの違いを体験してみてください.
以下二つをhtmlファイルに貼り付け,お好きなブラウザで開いてみてください.
うまく動作しない場合,以下のリポジトリをcloneしてファイルをブラウザに貼り付けてください.
https://github.com/YutaSeki36/reactSetStateDiff
クラス型コンポーネント
<!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>
関数型コンポーネント
<!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>
検証
それぞれ見た目は以下のようになるかと思います.

まずはクラス型コンポーネントの a+1
を押してみましょう.
このように,無事更新ができました.
次は関数型コンポーネントで動作確認を行なってみましょう.

このように,hooksでステートの更新を行うと,bがundefinedになってしまいました.
解決策
公式チュートリアルに,以下のような記述があります.
しかしクラスでの this.setState とは異なり、state 変数の更新は、マージではなく必ず古い値を置換します。
とありますので,hooksによるステート更新の際は古いステートもセットする必要があります.
先ほどの関数型コンポーネントファイルのステート更新mesoddo部分を以下のように書き換えます.
const handleChangeA = a => {
// スプレッド構文を用いて、古いステートも記述する
setState({ ...state, a: state.a + a });
};
結び
あまりReactに慣れていない状態でhooksに手を出してしまい,初歩的なところで躓いてしまいました.
しっかりと公式ドキュメントにも書いている内容だったため,今後新たな技術を学ぶ際は公式ドキュメントに目を通そうと思いました.
(誤字脱字,間違った内容などあればコメントください🙇♂️)