Setting Up Redux Observable

If you are adding redux observable to a new redux project, the first step is to install it along with RXJS

npm i redux-observable rxjs

The next step is to set up the middleware.

Create a middleware and pass it to the createStore function from Redux. Then you create a root epic that combines all your epics and call epicMiddleware.run() with the rootEpic.

import { createStore, compose, applyMiddleware } from 'redux';
import { createEpicMiddleware } from 'redux-observable';
import { combineEpics } from 'redux-observable';
import  { epicA } from './epicA';
import  { epicB } from './epicB';

export const rootEpic = combineEpics(
  epicA,
  epicB
);

const epicMiddleware = createEpicMiddleware();

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default function configureStore() {
  const store = createStore(
    rootReducer,
    composeEnhancers(
        applyMiddleware(epicMiddleware)
    )
  );

  epicMiddleware.run(rootEpic);

  return store;
}

If you are using redux Tooljit then you can replace the configureStore function with:

import { configureStore } from '@reduxjs/toolkit';

export default configureStore( {reducer: rootReducer, middleware: [epicMiddleware] } );

epicMiddleware.run(rootEpic);

export default configureStore( {reducer: rootReducer, middleware: [epicMiddleware] } );

epicMiddleware.run(rootEpic);


Now any epic you create will fire as soon as the app boots.

To call epics on demand, you filter then out of the action stream using `ofType`. So if you want to trigger the following epic then fire an action named `example/epicA`.

import {ofType} from “redux-observable”;

export const someEpic = action$ => action$.pipe(
ofType(‘example/epicA’),
delay(1000),
mapTo({ type: ‘example/epicB’ })
);


The last thing to consider is adding a global error handler to the root epic to catch bugs.

const rootEpic = (action$, store$, dependencies) =>
combineEpics(…epics)(action$, store$, dependencies).pipe(
catchError((error, source) => {
console.error(error);
return source;
})
);


# Resources
- [The official docs](https://redux-observable.js.org/docs/basics/SettingUpTheMiddleware.html) on setting up middleware.
- Redux now recommends writing actions as `domain/eventName` rather than `SCREAMING_SNAKE_CASE`. Don't believe me? [here you go](https://redux.js.org/style-guide/style-guide#write-action-types-as-domain-eventname).


Example Final Store.js for redux toolkit boilerplate

import { configureStore } from ‘@reduxjs/toolkit’;
import counterReducer from ‘../features/counter/counterSlice’;
import { createEpicMiddleware } from ‘redux-observable’;
import { combineEpics } from ‘redux-observable’;
import { combineReducers } from ‘redux’;
import { counterEpic } from ‘../features/counter/counterEpic’;
import {catchError} from ‘rxjs/operators’

export const epics = [
counterEpic
]

export const rootEpic = (action$, store$, dependencies) =>
combineEpics(…epics)(action$).pipe(
catchError((error, source) => {
console.error(error);
return source;
})
);

export const rootReducer = combineReducers({
counter: counterReducer
});

const epicMiddleware = createEpicMiddleware();

export default configureStore( {reducer: rootReducer, middleware: [epicMiddleware] } );

epicMiddleware.run(rootEpic);

 
1
Kudos
 
1
Kudos

Now read this

React Testing Library and Redux Observable

You can use the test scheduler to test sequences in epics but integration testing breakdown if you don’t include redux observable in your test redux wrapper. Here is how I successfully managed to integrate redux observable with react... Continue →