handleTransition's setState batched, actions not called
See original GitHub issueI’m using withStatechart and this parallel machine (simplified):
export default {
key: 'controller',
parallel: true,
states: {
NormalizeItems: {
initial: 'Normalizing',
states: {
Normalizing: {
on: {
NORMALIZE_SUCCESS: {
Normalizing: {
actions: ['startSessionSocket', 'subscribeItems'],
},
},
},
},
},
},
SessionSocket: {
initial: 'Disconnected',
states: {
Disconnected: {
on: {
START_SESSION_SOCKET: {
Connected: {
actions: ['joinSessionSocket'],
},
},
},
},
Connected: {
on: {
SESSION_SOCKET_SUBSCRIBE: {
Connected: {
actions: ['emitSubscribeItems'],
},
},
},
},
},
},
},
}
At some point, the first “child machine” calls startSessionSocket and subscribeItems, which look like this:
startSessionSocket = () => {
this.props.transition('START_SESSION_SOCKET')
}
subscribeItems = () => {
this.props.transition('SESSION_SOCKET_SUBSCRIBE')
}
This triggers the second child machine and should also call joinSessionSocket and emitSubscribeItems. However, only the second action (emitSubscribeItems) is called.
I suspect that’s because I call one transition after the other, sync, and setState gets batched by React here. And since runActionMethods is called by componentDidUpdate, the joinSessionSocket action is not called.
I understand you may not see this as a bug, and I could possibly fix this by grouping this to one transition / one action, but this happens in more places in the app and I figured such a fix doesn’t always result in maintainable code.
BTW: This component is one of the many “units” I have, and it has no UI. So I don’t care much about re-renders.
TL;DR: Action methods are called in componentDidUpdate. When React happens to batch multiple setState() calls in handleTransition, the machine itself is in the correct state (thanks to setState(prevState => ...)), but only actions from the last transition are called.
Issue Analytics
- State:
- Created 5 years ago
- Comments:26 (13 by maintainers)

Top Related StackOverflow Question
Thank you very much for your comments @lnogol @oliverhausler.
I closed this issue with a commit that prevents to fire consecutive transitions and enforces the intended behaviour.
For example, the following handler:
throws this error:
I’m not making any assumption but I couldn’t find a use-case where firing multiple tranisitions in the same “render” was the only option.
Joao, on Twitter, expressed a similar opinion:
Also, I disagree that “Using it for business logic like automata simply is an approach that doesn’t work”, I just think we need to find the correct approach to get the best of both worlds. For example, when I started using Flux I hated the “cannot dispatch in the middle of a dispatch” error until I learned how to use it properly.
In any case, feel free to reopen this issue and most importantly to propose solutions and/or submit PRs, I’ll be more than happy to discuss and review the code.
I will keep on thinking about this as well - it’s just that I couldn’t find a simple/clean solution and often, when this happens, it means I’m trying to solve the wrong problem : )
Thanks for your comment, @larsbuch. Would you be able to provide more information about your “concurrency” problem?