Description
For quite a while I've tried to understood why setState
is asynchronous. And failing to find an answer to it in the past, I came to the conclusion that it was for historical reasons and probably hard to change now. However @gaearon indicated there is a clear reason, so I am curious to find out :)
Anyway, here are the reasons I often hear, but I think they can't be everything as they are too easy to counter
Async setState is required for async rendering
Many initially think it is because of render efficiency. But I don't think that is the reason behind this behavior, because keeping setState sync with async rendering sounds trivial to me, something along the lines of:
Component.prototype.setState = (nextState) => {
this.state = nextState
if (!this.renderScheduled)
setImmediate(this.forceUpdate)
}
In fact, for example mobx-react
allows synchronous assignments to observables and still respect the async nature of rendering
Async setState is needed to know which state was rendered
The other argument I hear sometimes is that you want to reason about the state that was rendered, not the state that was requested. But I'm not sure this principle has much merit either. Conceptually it feels strange to me. Rendering is a side effect, state is about facts. Today, I am 32 years old, and next year I will turn 33, regardless whether the owning component manages to re-render this year or not :).
To draw a (probably not to good) parallel: If you wouldn't be able to read your last version of a self written word document until you printed it, that would be pretty awkward. I don't think for example game engines give you feedback on what state of the game was exactly rendered and which frames were dropped either.
An interesting observations: In 2 years mobx-react
nobody ever asked me the question: How do I know my observables are rendered? This question just seems not relevant very often.
I did encounter a few cases where knowing which data was rendered was relevant. The case I remember was where I needed to know the pixel dimensions of some data for layout purposes. But that was elegantly solved by using didComponentUpdate
and didn't really rely on setState
being async either. These cases seem so rare that it hardly justify to design the api primarily around them. If it can be done somehow, it suffices I think
I have no doubt that the React team is aware of the confusion the async nature of setState
often introduces, so I suspect there is another very good reason for the current semantics. Tell me more :)