2

Here's the working example in CodePen.

It has a button which toggles between ON and OFF

In React docs, it used prevState and updated the value of state.

    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));

It also produces the same result when I use the below method.

    this.setState({isToggleOn: !this.state.isToggleOn})

Could anyone suggest which one is good way and is recommended way to update the State the Component?

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
coderpc
  • 4,119
  • 6
  • 51
  • 93
  • Possible duplicate of [When to use React setState callback](https://stackoverflow.com/questions/42038590/when-to-use-react-setstate-callback) – Emile Bergeron Nov 27 '19 at 16:15
  • @EmileBergeron No, it is not. The purpose of this question is which way is good to update the state using `setState` but _not_ when to use `setState` callback as mentioned in your link. – coderpc Dec 23 '19 at 16:06
  • The duplicate target refer to both possible callback, [the _updater_ function](https://stackoverflow.com/a/49207167/1218980), and the callback after it's updated. – Emile Bergeron Dec 23 '19 at 17:27

2 Answers2

3

Because of to the asynchronous nature of setState, it is not advisable to use this.state to get the previous state within a setState. Instead, if you have to use the previous state, rely on the updater function approach.

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately. https://reactjs.org/docs/react-component.html#setstate

Elder
  • 1,475
  • 9
  • 17
  • 1
    You don't need to use the `setState` callback, to update a variable. The callback is used to do things when the `state` has actually been updated. – leofalmeida Nov 11 '19 at 19:24
  • You're correct, @leofalmeida. It's not the callback function, but the `updater` function. I updated my answer. – Elder Nov 11 '19 at 19:27
1

Like others said, you should do like you did in your first example.

It's rare that prevState => ({isToggleOn: !prevState.isToggleOn}) will yield a different result than that of {isToggleOn: !this.state.isToggleOn}, but it can happen.

It's generally recommended to always use the updater function whenever you are setting a new state that depends on the value of the old state.

Here are two snippets that demonstrate what can happen:

Passing an object to setState

Here, despite increasing the counter twice with setState it only increments by 1 each time.

class App extends React.Component {
  constructor() {
    super();
    this.state = {counter: 0};
    this.increment = this.increment.bind(this);
  }
  
  increment() {
    this.setState({counter: this.state.counter + 1});
    this.setState({counter: this.state.counter + 1});
  }
  
  render() {
    return (
      <div>
        <h3>{this.state.counter}</h3>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Passing an function to setState

Here, the counter increments correctly by 2.

class App extends React.Component {
  constructor() {
    super();
    this.state = {counter: 0};
    this.increment = this.increment.bind(this);
  }
  
  increment() {
    this.setState(prevState => ({counter: prevState.counter + 1}));
    this.setState(prevState => ({counter: prevState.counter + 1}));
  }
  
  render() {
    return (
      <div>
        <h3>{this.state.counter}</h3>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Community
  • 1
  • 1
Chris
  • 57,622
  • 19
  • 111
  • 137