Why does Inferno's setState is synchronous?



Because originally React was that way too. I think they changed it in v16. Inferno starts queuing Set state calls when you chain them. When this queuing process is in use then state changes get merged together. And it behaves like in React now.
So how can I chain them? Nothing works here...
class Abc extends Component {
state = {};
handleChange = (e: any) => {
console.log(1);
this.setState(() => ({a: e.target.value}));
this.setState(() => ({a: e.target.value}));
console.log(3);
};
render() {
console.log(2);
return <input type="text" value={this.state.a} onInput={this.handleChange} />;
}
}
Prints
1
2
2
3
Parent-to-child async setState also is not working:
class Abc extends Component {
state = {};
handleChange = (e: any) => {
this.props.onChange(e.target.value);
this.setState({a: e.target.value});
};
render() {
console.log(2);
return <input type="text" value={this.state.a} onInput={this.handleChange} />;
}
}
class Cba extends Component {
state = {};
handleChange = (a: any) => {
this.setState({a});
};
render() {
return <Abc onChange={this.handleChange} />;
}
}
<Cba />
Prints 2 2 times
I understand that it triggers only in lifecycle methods... Do you have any plans to expand that to event handlers?
Yeah that could be done. There might be some edge cases that needs to handled, but it should be doable
@qostya Do you have some arguments why it should do "async" -setState flow from delegated event handlers? Is it because React does so or is there another argument? What If React changes that, do we change then again?
IMO it would be much nicer to have async flow or sync flow always, but that is not compatible with React either.
@Havunen I think it's not just for React, but because we need the same and reusable api everywhere
@qostya Can you clarify what means everywhere in this context? Are you referring to infernojs APIs or other libraries?
Is the reason for async mainly so that state changes get queued?
I agree with @Havunen it would be nice if it was just simplified so setState was either always async or sync. Then another method could be added either setStateAsync or setStateSync to give the user control as to what to use.
@robbiespeed Yes, when it goes into "async" flow it will start merging state changes together to avoid diffing whole vNode tree multiple times. Its more about batching the updates together.
I think React does it that way too, only exception is that how event handlers are handled. See React setState is synchronous here:
https://jsfiddle.net/xaL8p1c6/
This version of fiddle is async because setState is triggered from event handler, like in the original post
https://jsfiddle.net/z40kvpca/
I understand, it seems like a very bad design if you can't be sure whether it's going to be async or sync. That should be chosen within the method, not left to be determined based on call site.
Can we get a code example of async setState from chaining?
Is the reason for async mainly so that state changes get queued?
I agree with @Havunen it would be nice if it was just simplified sosetStatewas either always async or sync. Then another method could be added eithersetStateAsyncorsetStateSyncto give the user control as to what to use.
I agree 100%. I would say since performance is so amazing to leave the implementation as is and then add two additional methods for sync and async.
Originally InfernoJS had setState and setStateSync but setStateSync was dropped due to problems it can cause. When the application grows one might accidentally enter into infinite loop using setStateSync version when those methods were merged into one at the same time setState was changed so that it automatically handles that infinite loop problem by queuing changes.
Can we get a code example of async setState from chaining?
In the previous post I added two jsFiddle examples from React where the order changes depending on how the code is called. Check console logs
Most helpful comment
Is the reason for async mainly so that state changes get queued?
I agree with @Havunen it would be nice if it was just simplified so
setStatewas either always async or sync. Then another method could be added eithersetStateAsyncorsetStateSyncto give the user control as to what to use.