[React]: setState (Asynchronous)
React
11/05/2019
Previously on setState()
In [React]: Basics, we've seen that setState() is a asynchronous function which does not happen immediately, but rather, happens in the future. Consider below situation where a button updates a value of state.
class App extends React.Component { constructor() { super(); this.state = { someVal: 33 }; }}
render() { return ( <div className="App"> <p>{this.state.someVal}</p> <button onClick={this.handleClick}>Update state</button> </div> );}
handleClick = () => { this.setState({ someVal: this.state.someVal + 1 }) console.log(this.state.someVal)}
Since setState() is asynchronous, the value doesn't get updated immediately on the console.
When using setState(), we give control to React library which figures out how to optimally update the state--React batches work into single update.
We've previously got around this by using a callback:
handleClick = () => { this.setState({ someVal: this.state.someVal + 1 }, () => console.log(this.state.someVal) )}
However, this is a bad practice. Having multiple setState(), won't guarantee that the new state variable is the latest version.
Rule of thumb is not to use this.state inside setState(), but instead, create a function.
What you should do
handleClick = () => { this.setState( (prevState, prevProps) => { return { someVal: prevState.someVal + 1 } }, () => console.log(this.state.someVal) )}
This uses a function instead of an object, and using a parameter prevState will give the latest value for update.
When you somehow need to manipulate state after the update, add into second parameter where the callback function is.
How about prevProps?
Here is how to pass down props onto App in index.js
ReactDOM.render(<App increment={1} />, document.getElementById("root"))
Then, use call it with
handleClick = () => { this.setState( (prevState, prevProps) => { return { someVal: prevState.someVal + prevProps.increment } }, () => console.log(this.state.someVal) )}
Using props in constructor
You can also pass in props into constructor
constructor(props){ super(props) this.state = { someVal: 33 };}
Allows to use props in constructor like
constructor(props){ super(props) this.state = { someVal: 33 + this.props.increment };}
By doing so, someVal will originally hold 35.
Alternate Class Syntax
Create React App allows Alternate Class Syntax which isn't allowed in the current JavaScript.
Example: Remove the constructor and just have state variable.
class App extends React.Component { state = { someVal: 33, }}
This initialize state as class field declaration.