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

React の setState() の引数が関数の場合とオブジェクトの場合の違いについて整理する

More than 1 year has passed since last update.

本稿のサンプルコードとデモサイトを用意しました。

概要

本稿では 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);

結果は下記のようになります。
Sep-30-2018 15-05-09.gif
ボタンをクリックするたびに 1 ずつカウントアップされています。

さて、それでは、それぞれのメソッド内で setState() を複数にした場合はどうなるでしょうか。

引数に関数を渡した場合

まずは、 setState() に関数を渡す場合について見ていきましょう。
このようにコードを書き換えた場合です。
ボタンがクリックされるたびに、state.count +2 されそうです。

...
handleClickFunction = () => {
  this.setState(prevState => {
    return { count: prevState.count + 1 };
  });
  this.setState(prevState => {
    return { count: prevState.count + 1 };
  });
};
...

結果はこのようになります。
Sep-30-2018 15-03-30.gif
いいですね。予期した動きになっています。

引数にオブジェクトを渡した場合

それでは、引数がオブジェクトの場合はどうでしょう。
コードをこのように変更します。

...
handleClickObject = () => {
  this.setState({ count: this.state.count + 1 });
  this.setState({ count: this.state.count + 1 });
};
...

結果は下記のとおりです。
Sep-30-2018 15-07-16.gif

引数にオブジェクトを渡した場合は単に、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

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
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