Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Truly batch actions with batch middleware #34

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

nbgraham
Copy link

@nbgraham nbgraham commented Aug 29, 2020

Fixes #23
Also, check out the discussion around this on the original batch middleware PR: #18

Problem:

Calling store.dispatch sends the action through all the middlewares again and updates the store.
So because the batch middleware dispatches each bundled action, the reducer receives each one and the state updates each time.
When using batch middleware, the store updates n times for a batch action with n actions, instead of 1 time.

Solution:

Whenever the batch middleware dispatches one of the bundled actions in a batch action, it marks it as unwrappedFromBatch. When this action comes back through the middlewares, the batch middleware looks for the unwrappedFromBatch flag and, if present, does nothing (does not call next, so it does not reach later middlewares nor the reducer/store to update).

I have used this approach with redux-saga successfully.

Tests Update

I added "integration tests" to test the behavior of the middleware in a real redux store.

At first glance, I thought the existing code would not send each bundled action to the reducer, because of this test:

	it('calls next only once, on the batchedAction', function() {
		const s = store()
		const next = sinon.spy()
		const batchAction = batchActions([action1, action2])
		batchDispatchMiddleware(s)(next)(batchAction)

		expect(next).to.have.been.calledWithExactly(batchAction)
		expect(next).to.have.callCount(1)
	})

However, this test is for the middleware in isolation, not in a redux store. So I added tests for the middleware behavior in a real redux store.

@tshelburne
Copy link
Owner

tshelburne commented Aug 19, 2022

Hi @nbgraham , I've not used Redux in years and consequently have totally neglected this PR. There was also some BS about a pandemic, etc...

Anyway, I'd like to give you commit access to this repo so that the code can stay alive. Let me know if interested.

@ericblade
Copy link

@nbgraham so, i just forked this to make it work with redux 5/rtk 2, and i thought i'd try out this change with it as well. I merged your change into my fork, and batchActions that are dispatched never hit. Am I misunderstanding something here, or is this just broken? Inspector shows it handling the BATCHING_REDUCER.BATCH action, but it doesn't show the actual batch being dispatched.

image

@ericblade
Copy link

ok, so... i dug into what this is doing and... no, you're not allowed to do that, and it doesn't work.

If you don't call next() for each relevant thing, then none of the reducers or middleware fire, so none of the data store gets updated, because the updates happen in the reducers. The whole idea is incorrect.

What you can do is not call next() for the item we are actually processing, ie, the batched request. Then that does not show up in the inspector, and reduces (har har) the number of reducer calls here by 1. You cannot reduce the number of calls TO 1. only BY 1. And that's if you want to make the assumption that you'll never need any other middleware or reducer to actually pay attention to the batch actions. That seems like a safe enough assumption, though. But if someone installs a middleware before the batch handler, then that can be done anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

batchDispatchMiddleware not batching action
3 participants