I seem to have encountered a situation where I cannot avoid the dispatch-within-a-dispatch problem in Flux.
I've read a few similar questions regarding this problem but none of them seem to have a good solution besides setTimeout
hacks, which I would like to avoid.
I'm actually using alt.js instead of Flux but I think the concepts are the same.
Imagine a component that initially renders a login form. When a user logs in, this triggers an XHR that eventually responds with authentication information (eg. the user name), and then fetches some secure data based on the authentication information and renders it instead of the login form.
The problem I have is when I attempt to fire an action to fetch data based on the XHR response, it is still in the dispatch of the LOGIN_RESPONSE
action, and triggers the dreaded
Error: Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.
I have created this jsfiddle to demonstrate the problem.
I have a Wrapper
component which either renders a login button or a Contents
child component, based on whether the user is set in MyStore
.
Wrapper
component.LOGIN
action.LOGIN_RESPONSE
action is dispatched (via the async mechanism in alt.js).MyStore
to update the user name.Wrapper
component observes the store change and updates its state.Wrapper
to render Content
component instead of the login button.Content
component, on mount, attempts to dispatch the FETCH_DATA
action, which fails because the dispatcher is still dispatching LOGIN_RESPONSE
. (If I wrap the FETCH_DATA
dispatch in a setTimeout
it works, but it feels like a hack).Variations of this seems to be a common scenario. In fact almost all the related questions have a similar scenario, but with no good or concrete answers.
Is there something intrinsically wrong with this data flow? What is the proper Flux way of doing something like this?
This is a common problem with dispatching in componentDidMount
in many libraries. The solution is to wrap dispatches in React's batched updates; luckily, Alt allows you to do this with the batchingFunction
option:
var alt = new Alt({
// React.addons.batchedUpdates is deprecated:
// batchingFunction: React.addons.batchedUpdates
// use this instead in newer versions of React
// see https://discuss.reactjs.org/t/any-plan-for-reactdom-unstable-batchedupdates/1978
batchingFunction: ReactDOM.unstable_batchedUpdates
});
See https://jsfiddle.net/BinaryMuse/qftyfjgy/ for a working example and this Fluxxor issue for a description of the same problem in a different framework.
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