Help us understand the problem. What is going on with this article?

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>

検証

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

スクリーンショット 2020-01-20 20.25.43.png

まずはクラス型コンポーネントの a+1 を押してみましょう.
スクリーンショット 2020-01-20 20.27.44.png

このように,無事更新ができました.

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

スクリーンショット 2020-01-20 20.29.37.png

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

解決策

公式チュートリアルに,以下のような記述があります.

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

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

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

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

これで無事にステート更新を行うことができました.
スクリーンショット 2020-01-20 20.38.32.png

結び

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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした