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

Fakes, spies, stubs & mocks

I learned how to test code using Jest. Today I’m working on a codebase that doesn’t have Jest and I have to use Jasmine and Sinon instead. The most confusing bit is going through the documentation and trying to understand what fakes,... Continue →