Skip to content

Commit c2aeff6

Browse files
committed
Warn When dispatching During Middleware Setup (#1485)
* Add a doc section on dispatching during middleware setup. * Warn when dispatching during middleware setup. * Upgrade the warning to an error. * Update docs to match thrown error behavior.
1 parent 0942183 commit c2aeff6

File tree

3 files changed

+22
-2
lines changed

3 files changed

+22
-2
lines changed

docs/advanced/Middleware.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,16 @@ The implementation of [`applyMiddleware()`](../api/applyMiddleware.md) that ship
265265

266266
* It only exposes a subset of the [store API](../api/Store.md) to the middleware: [`dispatch(action)`](../api/Store.md#dispatch) and [`getState()`](../api/Store.md#getState).
267267

268-
* It does a bit of trickery to make sure that if you call `store.dispatch(action)` from your middleware instead of `next(action)`, the action will actually travel the whole middleware chain again, including the current middleware. This is useful for asynchronous middleware, as we have seen [previously](AsyncActions.md).
268+
* It does a bit of trickery to make sure that if you call `store.dispatch(action)` from your middleware instead of `next(action)`, the action will actually travel the whole middleware chain again, including the current middleware. This is useful for asynchronous middleware, as we have seen [previously](AsyncActions.md). There is one caveat when calling `dispatch` during setup, described below.
269269

270270
* To ensure that you may only apply middleware once, it operates on `createStore()` rather than on `store` itself. Instead of `(store, middlewares) => store`, its signature is `(...middlewares) => (createStore) => createStore`.
271271

272272
Because it is cumbersome to apply functions to `createStore()` before using it, `createStore()` accepts an optional last argument to specify such functions.
273273

274+
#### Caveat: Dispatching During Setup
275+
276+
While `applyMiddleware` executes and sets up your middleware, the `store.dispatch` function will point to the vanilla version provided by `createStore`. Dispatching would result in no other middleware being applied. If you are expecting an interaction with another middleware during setup, you will probably be disappointed. Because of this unexpected behavior, `applyMiddleware` will throw an error if you try to dispatch an action before the set up completes. Instead, you should either communicate directly with that other middleware via a common object (for an API-calling middleware, this may be your API client object) or waiting until after the middleware is constructed with a callback.
277+
274278
### The Final Approach
275279

276280
Given this middleware we just wrote:

src/applyMiddleware.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ import compose from './compose'
1919
export default function applyMiddleware(...middlewares) {
2020
return (createStore) => (...args) => {
2121
const store = createStore(...args)
22-
let dispatch = store.dispatch
22+
let dispatch = () => {
23+
throw new Error(
24+
`Dispatching while constructing your middleware is not allowed. ` +
25+
`Other middleware would not be applied to this dispatch.`
26+
)
27+
}
2328
let chain = []
2429

2530
const middlewareAPI = {

test/applyMiddleware.spec.js

+11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ import { addTodo, addTodoAsync, addTodoIfEmpty } from './helpers/actionCreators'
44
import { thunk } from './helpers/middleware'
55

66
describe('applyMiddleware', () => {
7+
it('warns when dispatching during middleware setup', () => {
8+
function dispatchingMiddleware(store) {
9+
store.dispatch(addTodo('Dont dispatch in middleware setup'))
10+
return next => action => next(action)
11+
}
12+
13+
expect(() =>
14+
applyMiddleware(dispatchingMiddleware)(createStore)(reducers.todos)
15+
).toThrow()
16+
})
17+
718
it('wraps dispatch method with middleware once', () => {
819
function test(spyOnMethods) {
920
return methods => {

0 commit comments

Comments
 (0)