Closed nealoke closed 7 years ago
I'm running into the same issues and it seems that the actual problem is dispatching thunks within thunks, when the thunk is part of a batch.
Given this setup:
const store = createStore(
reducer,
compose(reduxBatch, applyMiddleware(thunk), reduxBatch)
);
The following works and will dispatch plainAction
twice:
const plainAction = { type: 'test' };
const thunkB = dispatch => dispatch(plainAction);
const thunkA = dispatch => dispatch(thunkB);
store.dispatch([plainAction, thunkA]);
Whereas this fails:
const plainAction = { type: 'test' };
const thunkB = dispatch => dispatch(plainAction);
const thunkA = dispatch => dispatch([thunkB]);
store.dispatch([plainAction, thunkA]);
The only difference here is that in the second example thunkB
is dispatched within a batch from thunkA
. The issue seems to be that the 2nd enhancer receives the raw store.dispatch
function and thus has no ability to handle thunks. Dispatching a non-batched thunk from a thunk within a 1st level batch works fine, because the thunk middleware itself can resolve the thunk instantly. It doesn't know how to handle batches though, so it passes them on, resulting in this issue.
Unfortunately that's more a Redux issue than redux-batch :/ If an action is handled by a middleware, it will never be able to dispatch an action that has to be handled by a previous middleware. Only next ones will be aware of this newly-generated action.
I think you might be able to do the following, but of course it's not very generic since it would only support two levels of thunks:
const store = createStore(
reducer,
compose(reduxBatch, applyMiddleware(thunk), reduxBatch, applyMiddleware(thunk), reduxBatch)
);
@arcanis Yeah I agree. The problem is inherently that something else than just a plain action is being dispatched. Solutions like sagas or epics are much more adequate for this because they only act upon generic actions and nothing special.
@johanneslumpe @arcanis yep seems clear. This is closed for now I guess. Thanks for the input guys 👍
With applyMiddleware
you can use something like
export function batchMiddleware() {
return function(next) {
return function dispatchRecurse(action) {
return Array.isArray(action)
? action.map(subAction => dispatchRecurse(subAction))
: next(action)
}
}
}
In combination with redux-batch enhancer subscribers will be notified only once, and your array actions will be dispatched through other middlewares sorry for my english, I hope idea is understandable
Status of this ?
I'm using your middleware which really is the best I could find! 👍
The only question I have is how to use this together with
redux-thunk
? I currently get the following error when I try to batch stuff action creators like this.What I'm trying to batch
Error log
Uncaught (in promise) Error: Actions must be plain objects. Use custom middleware for async actions.
Store setup
export default createStore(reducers, composeEnhancers(reduxBatch, applyMiddleware(ReduxThunk), reduxBatch));