Permalink
Browse files

fix(store.dispatch): Calling `store.dispatch()` directly in your Epic…

…s is now deprecated (#346)

The ability to call `store.dispatch()` inside your Epics was originally provided as an escape hatch, to be used rarely, if ever. Unfortunately in practice we've seen a large number of people using it extensively; there has even been popular tutorials teaching it as how you use redux-observable. Instead, Epics should emit actions through the Observable the Epic returns, using idiomatic RxJS.

```js
const somethingEpic = (action$, store) =>
  action$.ofType(SOMETHING)
    .switchMap(() =>
      ajax('/something')
        .do(() => store.dispatch({ type: SOMETHING_ELSE }))
        .map(response => ({ type: SUCCESS, response }))
    );
```

```js
const somethingEpic = action$ =>
  action$.ofType(SOMETHING)
    .switchMap(() =>
      ajax('/something')
        .mergeMap(response => Observable.of(
          { type: SOMETHING_ELSE },
          { type: SUCCESS, response }
        ))
    );
```

`store.dispatch` will be removed from Epics in v1.0.0 of redux-observable. This is unrelated to usage of `store.dispatch` inside your UI components--you will continue to use it there
  • Loading branch information...
jayphelps committed Oct 31, 2017
1 parent fb4a5af commit a1ba6a28bcf622743fa1102bb664e41134c56212
Showing with 13 additions and 2 deletions.
  1. +1 −1 docs/basics/Epics.md
  2. +1 −1 src/createEpicMiddleware.js
  3. +10 −0 src/utils/console.js
  4. +1 −0 test/createEpicMiddleware-spec.js
@@ -202,7 +202,7 @@ dispatch(incrementIfOdd());
```
> REMEMBER: When an Epic receives an action, it has already been run through your reducers and the state updated.
Using `store.dispatch()` inside your Epic is a handy escape hatch for quick hacks, but use it sparingly. It's considered an anti-pattern and we may remove it from future releases.
Using `store.dispatch()` inside your Epic is an anti-pattern and will be removed in v1.0.0 of redux-observable so it's best not to use it.

***

@@ -37,7 +37,7 @@ export function createEpicMiddleware(rootEpic, options = defaultOptions) {
const vault = (process.env.NODE_ENV === 'production') ? store : {
getState: store.getState,
dispatch: (action) => {
console.warn(`Your Epic "${epic.name || '<anonymous>'}" called store.dispatch directly. This is an anti-pattern.`);
require('./utils/console').deprecate('calling store.dispatch() directly in your Epics is deprecated and will be removed. Instead, emit actions through the Observable your Epic returns.\n\n https://goo.gl/WWNYSP');
return store.dispatch(action);
}
};
@@ -0,0 +1,10 @@
const deprecationsSeen = {};

export const deprecate = (typeof console === 'object' && typeof console.warn === 'function')
? msg => {
if (!deprecationsSeen[msg]) {
deprecationsSeen[msg] = true;
console.warn(`redux-observable | DEPRECATION: ${msg}`);
}
}
: () => {};
@@ -43,6 +43,7 @@ describe('createEpicMiddleware', () => {
store.dispatch({ type: 'PING' });

expect(console.warn.callCount).to.equal(1);
expect(console.warn.getCall(0).args[0]).to.equal('redux-observable | DEPRECATION: calling store.dispatch() directly in your Epics is deprecated and will be removed. Instead, emit actions through the Observable your Epic returns.\n\n https://goo.gl/WWNYSP');
console.warn.restore();
});

0 comments on commit a1ba6a2

Please sign in to comment.