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!
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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'/>
Method 2
Since setState is a async function. That means after calling setState state variable does not immediately change. So if you want to perform other actions immediately after changing the state you should use callback method of setstate inside your setState update function.
handleOnChange = (event) => { let inputState = event.target.checked; if(event.target.className == "barClubLounge") { this.setState({ barClubLounge: inputState}, () => { //here console.log(this.state.barClubLounge); //here you can call other functions which use this state variable // }); } }
Method 3
This is by-design due to performance considerations. setState in React is a function guaranteed to re-render Component, which is a costly CPU process. As such, its designers wanted to optimize by gathering multiple rendering actions into one, hence setState is asynchronous.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0