Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why calling setState method doesn't mutate the state immediately?

Ok, i'll try and make this quick because it SHOULD be an easy fix...

I've read a bunch of similar questions, and the answer seems to be quite obvious. Nothing I would ever have to look up in the first place! But... I am having an error that I cannot fathom how to fix or why its happening.

As follows:

class NightlifeTypes extends Component { constructor(props) {     super(props);      this.state = {         barClubLounge: false,         seeTheTown: true,         eventsEntertainment: true,         familyFriendlyOnly: false     }     this.handleOnChange = this.handleOnChange.bind(this); }  handleOnChange = (event) => {        if(event.target.className == "barClubLounge") {         this.setState({barClubLounge: event.target.checked});         console.log(event.target.checked)         console.log(this.state.barClubLounge)     } }  render() {     return (         <input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>     ) } 

More code surrounds this but this is where my problem lies. Should work, right?

I've also tried this:

handleOnChange = (event) => {    if(event.target.className == "barClubLounge") {     this.setState({barClubLounge: !this.state.barClubLounge});     console.log(event.target.checked)     console.log(this.state.barClubLounge) } 

So I have those two console.log()'s, both should be the same. I'm literally setting the state to be the same as the event.target.checked in the line above it!

But it always returns the opposite of what it should.

Same goes for when I use !this.state.barClubLounge; If it starts false, on my first click it remains false, even though whether the checkbox is checked or not is based off of the state!!

It's a crazy paradox and I have no idea whats going on, please help!

like image 231
Dan Avatar asked Mar 04 '17 07:03

Dan


People also ask

Why is setState not updating immediately?

setState function or the updater function returned by the React. useState() Hook in class and function components, respectively. State updates in React are asynchronous; when an update is requested, there is no guarantee that the updates will be made immediately.

Why are we using setState whereas not mutating the state?

Instead, we should use setState() . One reason is, for a pure component, directly mutating state won't trigger the component re-render, which could cause some odd bugs. With setState() we can change the state without directly mutating it.

Does setState work immediately?

setState or useState do not immediately mutate the state but create a pending state transition. Accessing state immediately after calling the updater method can potentially return the old value.

What happens when you call setState ()?

What setState does? setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.


1 Answers

Reason is setState is asynchronous, you can't expect the updated state value just after the setState, if you want to check the value use a callback method. Pass a method as callback that will be get executed after the setState complete its task.

Why setState is asynchronous ?

This is because setState alters the state and causes re rendering. This can be an expensive operation and making it synchronous might leave the browser unresponsive. Thus the setState calls are asynchronous as well as batched for better UI experience and performance.

From Doc:

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

Using callback method with setState:

To check the updated state value just after the setState, use a callback method like this:

setState({ key: value }, () => {      console.log('updated state value', this.state.key) }) 

Check this:

class NightlifeTypes extends React.Component {     constructor(props) {        super(props);          this.state = {           barClubLounge: false,           seeTheTown: true,           eventsEntertainment: true,           familyFriendlyOnly: false        }     }       handleOnChange = (event) => {  // Arrow function binds `this`        let value = event.target.checked;          if(event.target.className == "barClubLounge") {             this.setState({ barClubLounge: value}, () => {  //here               console.log(value);               console.log(this.state.barClubLounge);               //both will print same value           });                  }     }       render() {        return (            <input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>        )     }  }    ReactDOM.render(<NightlifeTypes/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>    <div id='app'/>
like image 158
Mayank Shukla Avatar answered Oct 13 '22 00:10

Mayank Shukla