Why there is no async getState function in React ?
Documentation tel us that setState is async. Fine, but that means we can't safely use this.state and we need an async getState as well to respect execution order.
From what I understand we should never use this.state and use a getState function like this :
getState(callback) {
this.setState((prevState) => {
callback(prevState) ;
});
}
...
this.getState((curState) => {
// we now can use the current state safely
}
Anything that I am missing here in my way of thinking ? Why no such function exists in React ?
-- EDIT --
As a friend of mine told me it was not clear and since I am not convinced but the first answer, let's analyze some piece of code :
simpleFunc() {
setState({ "counter" : 1 });
setState({ "counter" : 2 });
this.state.counter // => no garanty about the value
getState((curState) => { // ensure curState.counter is 2 });
}
This simple example shows that we can't use this.state directly in all situations since setState is async.
Here is a counter example where getState could be use : http://codepen.io/Epithor/pen/ZLavWR?editors=0010#0
Short answer: bad pratice, even not sure getState give us the current
The workaround is easy, but the fact that we can factorize some functions and use them without care about the context seems to be interesting, doesn't it ?
So, when many events occurs in a particular order, some events change the state, some read the state : how you can be sure, when an event read the state with this.state to read the good state since all changed are async ?
In fact all is about time :
T : event 1, change state
T+1ms : event 2, change state
T+2ms : event 3, read state
T+3ms : event 4, change state
As you can't predict when exactly will occurs the setState of event 1 or 2, how you could guarantee that event 3 will really read the state set at event 2 ?
Short answer: events are queued in JS stack whereas state changes are queued in internal React queue. Internal React queue is fully unstacked before giving the hand.
This function is used to update the state of a component, but it's important to remember that setState is asynchronous.
However it is easy to forget that the setState method is asynchronous, causing tricky to debug issues in your code. The setState function also does not return a Promise. Using async/await or anything similar will not work.
according to the official documentation of react, we can make setState synchronous by passing the callback function in the second argument.
getState()Returns the current state tree of your application. It is equal to the last value returned by the store's reducer.
You can definitely use this.state
directly in general. You should never mutate state directly (this.state.foo = 0
), and instead use setState
whenever you want to mutate state.
Usually a setState
looks like this:
this.setState({
foo: 0
})
Then you can safely use this.state.foo
eg in your render()
function.
There is a caveat however, in that due to the asynchronous nature of setState
, you have no guarantee you will have immediate access to this.state
after setState
has been called.
myFunc(baz) {
this.setState({
foo: baz + 1
})
console.log(this.state.foo) // not guaranteed
}
Better to do
myFunc(baz) {
const bazOne = baz + 1
this.setState({
foo: bazOne
})
console.log(bazOne)
}
Or use the setState
functions second parameter, used as a callback executed when the setState operation is finished. In that callback you will have access to the updated state, i.e. this.state
:
myFunc(baz) {
this.setState({ foo: baz + 1 }, () => {
console.log(this.state.foo) // guaranteed in callback
});
}
See: https://facebook.github.io/react/docs/react-component.html#setstate
It's actually not a bug/problem, but an architecture decision: the state
is not intended to be used as a simple property/variable/storage, it's specifically meant to be used for interface/visual state and, as such, don't need to be updated at every call. It uses an internal queue, so if you swap the state many times before rendering, it will actually update it only once with the final value and by the time render
method is invoked, it will contain the right value.
If you simply need to store/retrieve information during the execution or between methods that run in the same phase (componentWillReceiveProps
and shouldComponentUpdate
, for example), you can safely use this.anyProperty
as always:
componentWillReceiveProps() {
this.value = 'guaranteed';
return true;
}
shouldComponentUpdate() {
if (this.value === 'guaranteed') {
console.log('will always return true');
}
}
componentDidUpdate() {
this.value = ''; //cleanup
}
In the example above, if you used "setState" there would be no guarantee that the value would always be updated in "shouldComponentUpdate", but it shouldn't matter if you use it for its intended purpose. The state changes are guaranteed to have been flushed by render
time, so it should only contain information used in the rendering phase, not transactional/internal data for your objects. You are free to keep using object properties as usual.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With