Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. #133
Comments
My bad. I had the listener on the views misconfigured. The setTimeout trick actually works. |
Do you need to block the code execution while the long-running stuff is happening? If not, you might consider putting it in a promise, and then issuing the action when it's complete. This would be a bit more like the way XHR calls work -- the asynchronous nature of what you're doing is more upfront, rather than a hack at the end. The setTimeout trick is really a hack, and I think it's a somewhat dangerous habit to get into. Most of the time, these dispatch-within-a-dispatch errors are telling us that we have something wrong with our design, that we are thinking sequentially. The usual fix is to back up and build the second action into the first action. But with truly long-running stuff this isn't possible, and if an asynchronous solution is possible, it tends to be the best route. |
Yeah, it's a hack. I tried a few other things, like using a different store and putting a waitFor on the original store, but nothing helped except for this one thing. Using a promise might be more explicit, though, and I'll give that a try. Thanks, @fisherwebdev! |
So I'm having this same problem. I have a situation where I do need to chain actions.
I run into the "middle of a dispatch" scenario with this, as when the callback of the first action is fired, I would like to fire the second action based on the outcome of the first action (which I fire from the react component). I can't see a way to "back up and build the second action into the first action" as the firing of the second action completely depends on the result (ie the result of a calculation in the store) of the first one. I guess creating another store and using waitFor sounds like a solution, but to me that route seems to be deferring the problem, and results in the action being chained anyway, just across stores I've heard creating a queue is also another solution (#106), but again to me the net affect is that you have chained the actions anyway, and has also been suggested that that solution is not optimal as it requires trusting developers not to use AppDispatcher.assign() in the stores (I'm also not sure why we trust them not to fire actions in the stores, but seems that we can't trust them to not use AppDispatcher.assign() in stores) And setTimeout seems to work, but as suggested above, this may be a code smell as well? It seems the above are 3 ways to enable the chaining of actions in Flux, all are noted as "hacks" or sub optimal solutions, but I'm struggling to find an example of a design which avoids having to do the above, but still allowing me to do what I need to do. |
@adeperio I actually managed to get around this issue by adding more logic into my actions. You can also achieve the same effect by having the store just do everything, but to keep the store free of control flow logic, you can put this kind of decision into the actions. I also had to modify the original action trigger to send a bit more data to the action. |
I was thinking about this, and wanted to go down this route as well. The only thing was that actions would then need to observe state changes in the stores right which meant observing store states as the second action waited for the first? |
Not necessarily. If your actions depend on the state of the store, they aren't actions. The "view action" by definition is a UI event performed by a user. The "server action" is an event performed by the server, e.g. callback of an API call. All other events that stores perform, e.g. starting to fetch data, are internal events and shouldn't be called via actions. |
OK, so does that mean I should fire a http request from the Store? Using superagent my request would look something like the code below. If I run this code in the store wouldn't it mean that the server action would be triggered in the Store? If so does this break the Flux pattern?
|
That looks good to me. I use the same pattern but I placed it in an API adapter file that is solely responsible for data fetching, and it's called from a view action. |
I have an action that performs a long-running operation. When it's done, I want to tell it to signal it's done by dispatching another action. But when I do that, I come across the error above. My setup looks like this:
I also tried throwing the initDone() callback to the next event loop by delaying it for 1 ms. That prevented the error, but then the change event was not being picked up by the views.
The text was updated successfully, but these errors were encountered: