
Security News
Meet Socket at Black Hat and DEF CON 2025 in Las Vegas
Meet Socket at Black Hat & DEF CON 2025 for 1:1s, insider security talks at Allegiant Stadium, and a private dinner with top minds in software supply chain security.
redux-observable
Advanced tools
RxJS based middleware for Redux. Compose and cancel async actions and more.
redux-observable is a middleware for Redux that allows you to handle asynchronous actions using RxJS observables. It enables complex async flows in your Redux applications by leveraging the power of reactive programming.
Handling Asynchronous Actions
This feature allows you to handle asynchronous actions such as API calls. The example demonstrates an epic that listens for 'FETCH_USER' actions, makes an AJAX request to fetch user data, and dispatches either a 'FETCH_USER_FULFILLED' or 'FETCH_USER_FAILED' action based on the result.
const fetchUserEpic = action$ => action$.pipe(
ofType('FETCH_USER'),
mergeMap(action =>
ajax.getJSON(`/api/users/${action.payload}`).pipe(
map(response => ({ type: 'FETCH_USER_FULFILLED', payload: response })),
catchError(error => of({ type: 'FETCH_USER_FAILED', payload: error }))
)
)
);
Combining Multiple Epics
redux-observable allows you to combine multiple epics into a single root epic. This is useful for organizing your code and managing complex async flows. The example shows how to combine `fetchUserEpic` with another epic.
const rootEpic = combineEpics(
fetchUserEpic,
anotherEpic
);
Cancellation of Actions
redux-observable supports the cancellation of ongoing actions. The example demonstrates using `switchMap` to cancel any ongoing AJAX request if a new 'FETCH_USER' action is dispatched, ensuring only the latest request is processed.
const fetchUserEpic = action$ => action$.pipe(
ofType('FETCH_USER'),
switchMap(action =>
ajax.getJSON(`/api/users/${action.payload}`).pipe(
map(response => ({ type: 'FETCH_USER_FULFILLED', payload: response })),
catchError(error => of({ type: 'FETCH_USER_FAILED', payload: error }))
)
)
);
redux-saga is a middleware for Redux that uses generator functions to handle side effects. It is similar to redux-observable in that it helps manage complex async flows, but it uses a different approach based on ES6 generators rather than RxJS observables.
redux-thunk is a middleware that allows you to write action creators that return a function instead of an action. It is simpler than redux-observable and redux-saga, making it a good choice for handling basic async actions without the need for complex flow control.
redux-promise-middleware is a middleware that allows you to dispatch promises as actions. It automatically dispatches pending, fulfilled, and rejected actions based on the promise's state. It is less powerful than redux-observable but can be useful for straightforward async operations.
RxJS 5-based middleware for Redux. Compose and cancel async actions and more.
takeUntil
or zip
)NOTE: This has a peer dependencies of rxjs@5.0.*
and redux
, which will have to be installed
as well.
npm install --save redux-observable
Add the middlware to your redux store:
import { createStore, applyMiddleware } from 'redux';
import { reduxObservable } from 'redux-observable';
const store = createStore(
rootReducer,
// Notice that we invoke `reduxObservable()` before passing it!
applyMiddleware(reduxObservable())
);
With redux-observable, you can dispatch any function that returns an observable, a promise, an observable-like object or an iterable; we call this a "thunkservable".
Your thunkservable emits a stream of actions.
Here are several examples:
// using RxJS
dispatch(() => Rx.Observable.of({ type: 'ASYNC_ACTION_FROM_RX' }).delay(1000));
// using a Promise
dispatch(() => Promise.resolve({ type: 'ASYNC_ACTION_FROM_PROMISE'}));
// using an Array of actions
dispatch(() => [{ type: 'ACTION_1' }, { type: 'ACTION_2' }]);
// using a generator of actions
dispatch(() => (function* () {
for (let i = 0; i < 10; i++) {
yield { type: 'SOME_GENERATED_ACTION', value: i };
}
}()));
Of course, you'll usually create action factories instead:
const asyncAction = () => (
(actions, store) => Rx.Observable.of({ type: 'ASYNC_ACTION_FROM_RX' }).delay(1000)
);
dispatch(asyncAction());
const fetchUserById = (userId) => (
(actions) => (
Rx.Observable.ajax(`/api/users/${userId}`)
.map(
(payload) => ({ type: 'FETCH_USER_FULFILLED', payload })
)
.startWith({ type: 'FETCH_USER_PENDING' })
)
);
dispatch(fetchUserById(123));
// If you find it more readable, you certainly can omit all those
// arrow function parenthesis (or use regular functions)
const fetchUserById = userId =>
actions =>
Rx.Observable.ajax(`/api/users/${userId}`)
.map(payload => ({ type: 'FETCH_USER_FULFILLED', payload }))
.startWith({ type: 'FETCH_USER_PENDING' });
It's recommended to dispatch an action to cancel your async action with Rx. This can be done
by leveraging the first argument to your dispatched function, which returns an observable of all actions
.
This observable is an instanceof ActionObservable
and has a custom operator ofType
. The ofType
operator can be used to filter down to a set of actions of a particular type. It is essentially an alias
for filter(action.type === 'SOME_TYPE')
. You can use this stream of all actions with operators like
takeUntil
to abort the async action cleanly and via composition.
dispatch(
(actions) => Observable.timer(1000)
.map(() => ({ type: 'TIMER_COMPLETE'}))
.takeUntil(
actions.ofType('ABORT_TIMER')
)
// `actions.ofType('ABORT_TIMER')` is equivalent to
// `actions.filter(action => action.type === 'ABORT_TIMER')`
);
// elsewhere in your code you can abort with a simple dispatch
dispatch({ type: 'ABORT_TIMER' });
You can also cancel an async dispatch by using the return value from your dispatch, which is an Rx Subscription. This works well for other types that don't have cancellation, like promises, but internally will really use "disinterest" to stop the resolved value from propagating.
let subscription = dispatch(() => Promise.resolve({ type: 'DELAYED_ACTION' }));
// will stop DELAYED_ACTION from firing
subscription.unsubscribe();
The second argument to your dispatched function will be the store
instance itself. This gives you
the ability to getState()
on your store in case you need to assert some condition before dispatching your
next async message. It also gives you the ability to dispatch()
explicitly.
If it helps to think about it this way, in a TypeScript-style type definition, the dispatch function would look like this when used to dispatch an action asynchronously:
dispatch = ((actions?: Observable<Action>, store?: ReduxStore) => Observable<Action>) => Subscription;
A full example is available in examples/basic
Since redux-observable uses dispached functions, this middlware is incompatible with redux-thunk. At this time, this is unavoidable since providing the function a stream of future actions for cancellation is imperative.
:shipit:
FAQs
RxJS based middleware for Redux. Compose and cancel async actions and more.
The npm package redux-observable receives a total of 212,313 weekly downloads. As such, redux-observable popularity was classified as popular.
We found that redux-observable demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Meet Socket at Black Hat & DEF CON 2025 for 1:1s, insider security talks at Allegiant Stadium, and a private dinner with top minds in software supply chain security.
Security News
CAI is a new open source AI framework that automates penetration testing tasks like scanning and exploitation up to 3,600× faster than humans.
Security News
Deno 2.4 brings back bundling, improves dependency updates and telemetry, and makes the runtime more practical for real-world JavaScript projects.