本稿のサンプルコードとデモサイトを用意しました。
概要
本稿では React の setState()
の引数に関数を渡す場合と、オブジェクトを渡す場合の挙動の差異についてまとめます。
React では setState()
を使って state の変更ができます。 setState()
には引数に関数かオブジェクトを渡せますが、 オブジェクトを渡したときは予期せぬ動作になるかもしれないよ ということについて書きます。
サンプルアプリ
それぞれの挙動を見るにあたって下記のサンプルコードを使います。
ボタンがクリックされるたびに state.count
が +1 される単純なアプリです。
import React, { Component } from "react";
import ReactDOM from "react-dom";
class Counter extends Component {
state = {
count: 0
};
render() {
return (
<div>
<h1>Count: {this.state.count}</h1>
<button onClick={this.handleClickFunction}>Count up</button>
<button onClick={this.handleClickObject}>Count up</button>
</div>
);
}
handleClickFunction = () => {
this.setState(prevState => {
return { count: prevState.count + 1 };
});
};
handleClickObject = () => {
this.setState({ count: this.state.count + 1 });
};
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Counter />, rootElement);
結果は下記のようになります。
ボタンをクリックするたびに 1 ずつカウントアップされています。
さて、それでは、それぞれのメソッド内で setState()
を複数にした場合はどうなるでしょうか。
引数に関数を渡した場合
まずは、 setState()
に関数を渡す場合について見ていきましょう。
このようにコードを書き換えた場合です。
ボタンがクリックされるたびに、state.count
+2 されそうです。
...
handleClickFunction = () => {
this.setState(prevState => {
return { count: prevState.count + 1 };
});
this.setState(prevState => {
return { count: prevState.count + 1 };
});
};
...
結果はこのようになります。
いいですね。予期した動きになっています。
引数にオブジェクトを渡した場合
それでは、引数がオブジェクトの場合はどうでしょう。
コードをこのように変更します。
...
handleClickObject = () => {
this.setState({ count: this.state.count + 1 });
this.setState({ count: this.state.count + 1 });
};
...
引数にオブジェクトを渡した場合は単に、state.count
に +1 した場合と同じ挙動になっています。
なぜこうなるのか
setState()
は、引数に オブジェクトが渡された場合 に、 state を即時にアップデートすることを 保証しません。
Reactは、パフォーマンスを高めるため、複数の setState()
を単一の更新にバッチするためです。
そのため、1つの関数内で state の更新を連続的に行うときは、引数に関数を渡しましょう。
まとめ
関数を渡す場合とオブジェクトを渡す場合の違いについて書いてある記事があまりなかったので書きました。
本稿の内容は参考に載せた React のドキュメントに詳しく書いてあります。
サンプルコードとデモサイト
本稿の内容の最終的なコードを下記に用意してあります。
im36-123/differences_of_set_state
デモサイト
参考
React.Component – React
Component State – React
State and Lifecycle – React