RxJS middleware for action side effects in Redux using "Epics"

Related tags

redux-observable
Overview

Join the chat at https://gitter.im/redux-observable/redux-observable build status npm version npm downloads code climate Greenkeeper badge

RxJS-based middleware for Redux. Compose and cancel async actions to create side effects and more.

https://redux-observable.js.org

Install

This has peer dependencies of [email protected] and [email protected], which will have to be installed as well.

npm install --save redux-observable
UMD

We publish a UMD build inside our npm package. You can use it via the unpkg CDN:

https://unpkg.com/[email protected]/dist/redux-observable.min.js

Watch an introduction

Watch a video on redux-observable

Documentation

https://redux-observable.js.org

Discuss

Join the chat at https://gitter.im/redux-observable/redux-observable

Everyone is welcome on our Gitter channel!

Custom Emoji

Save this:

Add the redux-observable spinning logo to your Slack channel! Slack Instructions


*redux-observable is a community-driven, entirely volunteer project and is not officially affiliated with or sponsored by any company.

:shipit:

Issues
  • RFC: provide state$ as a stream argument

    RFC: provide state$ as a stream argument

    The store provided by redux (and given to Epics) isn't a full store, so it doesn't have the store[Symbol.observable]() interop point to support Observable.from(store). This is by their design.

    Let's consider changing the Epic signature to function (action$: ActionsObservable, state$: BehaviorSubject<State>, store: Store), making a stream of stage changes the second argument and moving the store to the third argument.

    const fetchUserEpic = (action$, state$) =>
      action$.ofType(FETCH_USER)
        .mergeMap(action =>
          getJson(`/users/${action.id}`, { 'Authorization': `Bearer ${state$.value.authToken}` })
            .map(respose => fetchUserFulfilled(response))
        );
    
    // or the "reactive" way, but more verbose
    
    const fetchUserEpic = (action$, state$) =>
      action$.ofType(FETCH_USER)
        .withLatestFrom(state$.pluck('authToken'))
        .mergeMap(([action, authToken]) =>
          getJson(`/users/${action.id}`, { 'Authorization': `Bearer ${authToken}` })
            .map(respose => fetchUserFulfilled(response))
        );
    
    const localStorageStateEpic = (action$, state$) =>
      state$
        .filter(state => state.someState)
        .distinctUntilChanged() // state is supposed to be immutable, so this should be safe
        .throttleTime(500) // may or may not want to do something like this for perf reasons
        .do(state => localStorage.setItem('someState', JSON.stringify(state)))
        .ignoreElements(); // we have no actions to emit
    

    I'd want to keep the store still, since while not necessarily idiomatic to use, is a handy escape hatch to "get shit done".

    If this is a good idea in general, we'd need to decide what kind of observable the state changes were in. My initial thoughts were a BehaviorSubject so that the imperative value property was available for the same common cases people use store.getState() for or they can operate on it and it emit the last value right away. ~~Because it's an observable, it feels slightly more idiomatic and then people don't need to learn about the fact that Redux's store supports the Symbol.observable interop so you could just do Observable.from(store), which isn't immediately obvious.~~

    Obviously, this is not really all that different than existing solution..it's more whether we should provide a obvious "Rx way" or not. Please feel free to debate this.

    Cc/ @blesh

    feature request RFC 
    opened by jayphelps 38
  • Process Manager dispatch multiple actions

    Process Manager dispatch multiple actions

    I tried to return an array of action objects from the observable, Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.

    It would be great if it worked, then I could dispatch to a logger or notification component, for success and errors.

    opened by beckend 38
  • WIP: provide server side rendering support via sigterm/sigkill

    WIP: provide server side rendering support via sigterm/sigkill

    opened by hitmands 38
  • Sequencing actions together

    Sequencing actions together

    This is a fantastic library. Thank you for sharing!

    Would it possible to provide an example that composes two asynchronous actions together into one asynchronous action that is cancelable?

    I believe it is possible however struggling at the movement to get my head around it.

    question 
    opened by nathanvale 37
  • Add extraArgument to reduxObservable

    Add extraArgument to reduxObservable

    The same idea as at this redux-thunk PR

    (People often request the ability to inject a custom argument into thunks.)

    And I really need this ability ;-)

    opened by istarkov 30
  • Uncaught errors from promises getting swallowed when running in Jest

    Uncaught errors from promises getting swallowed when running in Jest

    Example:

    const ohNoEpic = action$ => action$
      .ofType('OH_NO') // where OH_NO is some real action type that will be matched
      .mergeMap(() =>
        Observable.fromPromise(new Promise(() => { throw Error('oh no') }))
      )
    

    In the browser this yields a stack trace on the console... in Jest, nothing happens. If the promise was a real epic that was being tested, the test would eventually time out, with no useful error message being printed.

    opened by pelotom 29
  • redux-epic and redux-observable

    redux-epic and redux-observable

    Hello Everyone,

    I'm the creator of Redux-Epic, which is a redux library in similar fashion to redux-saga but built using RxJs with first class support for SSR.

    In https://github.com/BerkeleyTrue/redux-epic/issues/13 it has been brought to my attention that this library has arrived at the same path as redux-epic, triggering observable in middleware a la redux-saga.

    But there are also various differences that I go into detail in the issue above.

    I'm opening this issue to discuss whether merging the two products would benefit everybody and whether the goals I've laid out for redux-epic are compatible with the goals of redux-observable.

    • First class support for SSR
    • Designed for Universal JavaScript (read: Isomorphic)
    • Ability to inject dependencies
    • Disposable Epics
    opened by BerkeleyTrue 25
  • Add error handling examples

    Add error handling examples

    Hi,

    I think it's not clear right now how to handle errors with this middleware. There is no example of it in the basic example nor the medium article.

    Lets say I have this action creator:

    function createRequestAction({request, success, failure, abort}, fetch) {
        return payload => actions => Rx.Observable
                .fromPromise(fetch(payload))
                .map(success)
                .takeUntil(actions.ofType(abort.toString()))
                .startWith(request());
    }
    
    const getUser = createRequestAction(userActions, fetchUser);
    
    // ...
    store.dispatch(getUser({id: 123}));
    

    If the promise returned by fetchUser fail, it will just throw an error and I don't see any way to handle it in a proper RxJS fashion. In RxJS v4 there was a catch method, but now there isn't. How should i properly dispatch the failure error when the request fail?

    examples 
    opened by Madumo 22
  • An in-range update of webpack is breaking the build 🚨

    An in-range update of webpack is breaking the build 🚨

    The devDependency webpack was updated from 4.19.1 to 4.20.0.

    🚨 View failing branch.

    This version is covered by your current version range and after updating it in your project the build failed.

    webpack is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

    Status Details
    • continuous-integration/travis-ci/push: The Travis CI build failed (Details).

    Commits

    The new version differs by 40 commits.

    • c4d8a3c 4.20.0
    • 1495b33 Merge pull request #8070 from chuckdumont/work
    • 434ced3 Merge pull request #8071 from timneutkens/fix/typo
    • 2671d88 Fix typo
    • f8877e0 Uncaught exception from renderers
    • 31d735c Merge pull request #8068 from webpack/feature/json-to-typescript
    • 762b1c9 move json-schema-to-typescript to devDependencies
    • 9c8f304 Merge pull request #8065 from webpack/ci/appveyor
    • 3b6d149 Merge pull request #7232 from webpack/feature/json-to-typescript
    • 61718d4 Merge pull request #8064 from xtuc/chore-bump-webassemblyjs13
    • f8bc251 Reduce the appveyor CI tasks
    • 62b6142 fix Validation test
    • c768182 fix issues with absolutePath, allOf and anyOf
    • 8c31f2a fixes for RegExp in schema
    • 44955b7 emit exit code only in lint mode

    There are 40 commits in total.

    See the full diff

    FAQ and help

    There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


    Your Greenkeeper Bot :palm_tree:

    greenkeeper 
    opened by greenkeeper[bot] 22
  • Question re: SSR

    Question re: SSR

    If I use React Router's match function, and trigger actions from all matched components, is there a good way to coordinate when all these actions (Observables) are completed? This would be essential for SSR, and is normally coordinated with Promises and Promise.all.

    question 
    opened by StevenLangbroek 21
  • V2 Imports RxJS 7 inside RxJS 6 apps/bundles (and also provoke breaking changes)

    V2 Imports RxJS 7 inside RxJS 6 apps/bundles (and also provoke breaking changes)

    The README of the package says:

    This has peer dependencies of [email protected] and [email protected], which will have to be installed as well.

    which is untrue since rxjs is listed as direct dependency and on version 7. This makes bundlers put 2 versions of RxJS inside final bundle which is a bad thing. Shouldn't rxjs be listed as a peerDependency like stated originally? I would be happy to open a PR to rectify this, just need to know if you want to keep it as dependency or not. In any case, putting RxJS 7 as direct dependency is a breaking change as it renders this library incompatible with version 6 (specially if you were using StateObservable to write your tests because the subscriber signature changed). My take on this would be to remove RxJS as direct dependency and put it as peer as people want to be in control of their RxJS version and update the README+CHANGELOG accordingly.

    For reference, this is the error you get if you give an RxJS 6 Observable to the V2 StateObservable:

    Screenshot 2021-09-19 at 00 07 43
    opened by D34THWINGS 1
  • feat(ofType): narrow type of output based on action type

    feat(ofType): narrow type of output based on action type

    opened by thynson 9
  • Better Troubleshooting and Cancellation Docs

    Better Troubleshooting and Cancellation Docs

    Changes:

    • All the links have been updated to the latest rxjs docs.
    • Headings have been reformatted to be more standard.
    • Fixed some grammar.
    • Particular to Troubleshooting.md
      • Workarounds have been added for the ofType operator issue.
    • Particular to Cancellation.md
      • Examples have been improved.
      • Remarks have been improved.
    opened by jun-sheaf 1
  • Usage with redux toolkit

    Usage with redux toolkit

    I might turn this into a docs page. Let me know if this is clear enough.

    Basic gist for typescript is that you don't create a union of all your action types because they will just be string. Use the .match on an action instead to have the payload typed in your epics.

    For JavaScript just delete everything with a squiggly red line

    import {
      AnyAction,
      combineReducers,
      configureStore,
      createSlice,
      PayloadAction,
      getDefaultMiddleware
    } from "@reduxjs/toolkit";
    import { createEpicMiddleware, Epic } from "redux-observable";
    import { filter, map, delay } from "rxjs/operators";
    
    export const counter = createSlice({
      name: "counter",
      initialState: 0,
      reducers: {
        increment: (state, action: PayloadAction<number>) => state + action.payload,
        decrement: (state, action: PayloadAction<number>) => state - action.payload
      }
    });
    
    const reducer = combineReducers({
      counter: counter.reducer
    });
    
    export type MyState = ReturnType<typeof reducer>;
    
    export type MyEpic = Epic<AnyAction, AnyAction, MyState>;
    
    const countEpic: MyEpic = action$ =>
      action$.pipe(
        filter(counter.actions.increment.match),
        delay(500),
        map(action => counter.actions.decrement(action.payload))
      );
    
    const epicMiddleware = createEpicMiddleware<AnyAction, AnyAction, MyState>();
    
    export const store = configureStore({
      reducer,
      middleware: [
        ...getDefaultMiddleware({
          thunk: false // or true if you want to use thunks
        }),
        epicMiddleware
      ]
    });
    
    epicMiddleware.run(countEpic);
    
    examples 
    opened by evertbouw 9
  • What is the right way to register EPIC  in Angular 8 app module,

    What is the right way to register EPIC in Angular 8 app module,

    Am new to redux, and my first encounter landed me in using epic, but i have one problem connectng epic with my store in my app module, am using angular. The Action Creators

    this is action creator defined inside a class

      ` static LIST_ALL_COMPETITIONS = 'LIST_ALL_COMPETITIONS';
         listAllCompetition(payload : ICompetition[]) : AnyAction {
           return this.ngRedux.dispatch(
             { type: SessionActions.LIST_ALL_COMPETITIONS, 
           payload});
     };`
    

    i would want this action dispatched if a user hit my url in the browser, kind of fetching the data from the server, so i would probably call this in my ngOnit or use a resolver in the route path.

    The Reducer Function

    My reducer function will take an initial state that comprises of the different endpoint that will prefetch which of course has the same structure with the remote data which i enforced by creating each interface for each endpoint.

      ` export const initialState:IAppState = {
         competitions: [],
         matches:[],
         teams : [],
         standing: [],
         players:[]
       }
     export function FootballReducer(state: IAppState = initialState, action){
         switch(action.type){
            case ActionTypes.ListCompetitionSuccess:
                return{
                    ...state, 
                    competitions: action.payload
               }     
         }
        return state;
    }`
    

    if am able to setup epic correctly, it suppose the intercept the actions coming in from the component, do the network call and return an action containing the payload of the fetched result

     `constructor(private http: HttpClient, private service : FootballStoreService, private action : 
        SessionActions ) { }
         listAllCompetitions  = (action$) : AnyAction => {
           return action$.pipe(
             ofType(SessionActions.LIST_ALL_COMPETITIONS),
                mergeMap(() => {
                   return this.service.listAllCompetition()
                     .map(result => {
                     return this.action.listAllCompetition(result)
          })
          .catch(error => Observable.of({
            type: SessionActions.ERROR_LIST
          }));
        }))
     }`
    

    the function that makes the api call

    `listAllCompetition(){
     return this.http.get<ICompetition[]>(BASE_URL+'competitions/', {headers: this.headers})
    }`
    

    the issue now is configuring epic to create a store at my app module. another thing am unsure of is whether an setting up epic correctly interm of my reducer and action, i need explanations on this.

    the app module congif

    `export class AppModule {
       constructor(private ngRedux : NgRedux<IAppState>, private epic : EpicServiceService){
         const epicActiion = createEpicMiddleware(this.epic.listAllCompetitions(this is where the 
      problem is, bringing in my epic funtions here))
         // const middleWare = [createEpicMiddleware(SessionActions.LIST_ALL_COMPETITIONS)];
          ngRedux.configureStore(
          FootballReducer, 
         initialState
         )
         }
     }`
    

    my problem is that the createmiddleWare functions needs a action type and i don't know how to feed it that argument.

    Setting up the store including epic middleware shouldn't be made too complicated, redux on its own is already confusing, if somebody is able to learn what an actions is, and where the reducer functions comes in, bringing in epic as a tool that will aid side effects should be made easy to integrate. so pls with the latest release of RxJS library, point me to a link that can detail how to work with redux and observable using epic as it relate to my reducers and actions. but better still somebody here can guide with code snippets on the best practice.

    Originally posted by @myquery in https://github.com/redux-observable/redux-observable/issues/78#issuecomment-569284193

    opened by myquery 0
  • Linked documentation in warning is not found

    Linked documentation in warning is not found

    EDIT BY @jayphelps: Google killed the link, but I believe it pointed to the original issue ticket here: https://github.com/redux-observable/redux-observable/issues/389


    Description

    The link, https://goo.gl/2GQ7Da in warning does not exist.
    (Error occurs even with all ad-blockers turned off)

    image

    The warning below is found here - https://github.com/redux-observable/redux-observable/blob/16f083d405/src/createEpicMiddleware.ts#L49

    warn(
      'this middleware is already associated with a store. createEpicMiddleware should be called for every store.\n\nLearn more: https://goo.gl/2GQ7Da'
    );
    

    image

    Additional Context

    These are not directly related but added for completeness.

    • Redux-Observable version: v1.2.0
    • Site framework: Next.js v9.1.4
    • OS: Windows 10 build 1903.
    • Browser: All browsers (Used Brave in the screenshot)

    Searching for https://goo.gl/2GQ7Da in the issue shows Server Side Rendering Documentation (not a dupe), which I will be checking out for the warning.

    v2.0.0 
    opened by dance2die 4
  • Implementing SSR in large commercial project.

    Implementing SSR in large commercial project.

    Hi guys, We have quite large commerce app. We need to implement SSR however our whole communication is going through redux-observable. Previous developer recommend to rewrite all epics to redux-saga. We have them more then 50.

    What do you think, should we do this migration or we maybe we should develop own solution based onthis PR?

    Or maybe this solution would be still working?

    I also found react-redux-epic library. Guy here said 18 days ago that he is still using it and its working.

    Our epics are in most cases are very simple. Mostly we do some ajax calls and fill store with data. Sometimes we do some transformations or we dispatch other actions, but in general they are pretty straightforward.

    All we need to do on server is to dispatch few actions (the same we have in componentDidMount) and wait for other few actions to be dispatched (success actions).

    Maybe you know how to listen on action$ in server function?

    What do you think we should start migration of 50 (or even more) epics to redux-saga or we should spend few days on getting working redux-observable event if ssr is not nativly supported?

    I am using redux-observable for few years now but I don't feel strong enough to make decision at least now.

    Btw redux-saga based on promise but I always though that streams are just more advanced promises. :)

    Have a good day and thanks for any response :)

    opened by Tarvald 13
  • Added improved method of logging errors

    Added improved method of logging errors

    Reason for PR

    I noticed combineEpics doesn't do anything to help locate errors. Almost always, when using redux-observable, it's nearly impossible to find errors unless you've got a catchError at the bottom of your pipeline.

    In my own Redux-less implementation of Redux-Observable, I added this functionality:

    | createRootEpic | catchEpicError | |:---:|:---:| | createRootEpic | catchEpicError |

    Not only does this implementation include a way of logging errors as actions, it also logs them to the console with the name of the Epic that caused the error.

    It's super helpful in debugging. combineEpics could definitely benefit from functionality like this.

    In case there's a stack available such as the error being an EventError (Node.js), one of my other versions of this operator checks for stack information.

    image

    Changes

    This method makes it obvious which epic actually threw an error and then throws it again so it proceeds as usual similar to doing a Promise.prototype.catch and throwing the error again so the next .catch picks it up.

    Just like when throwing a TypeError, this also utilizes epic.name.

    opened by Sawtaytoes 10
  • Server Side Rendering Documentation

    Server Side Rendering Documentation

    Do you want to request a feature or report a bug?

    Don't find official documentation on SSR.

    What is the current behavior? It doesn't work on the server side or throws the following warning.

    Learn more: https://goo.gl/2GQ7Da
    redux-observable | WARNING: this middleware is already associated with a store. createEpicMiddleware should be called for every store.
    
    

    If the current behavior is a bug, please provide the steps to reproduce and a minimal demo of the problem using JSBin, StackBlitz, or similar.

    What is the expected behavior?

    Should work SSR. Which versions of redux-observable, and which browser and OS are affected by this issue? Did this work in previous versions of redux-observable? 1.1.0

    opened by veeramarni 2
  • Feature proposal: createDependencies option for createEpicMiddleware

    Feature proposal: createDependencies option for createEpicMiddleware

    Hello!

    When developing with redux-observable, we end up repeating the common pattern of passing state$ to any dependency. For example, we have a request dependency which is a wrapper around rxjs/ajax. We pass state$ to that function on every single call so that it can take the API token from the state and update the request headers accordingly.

    My proposition is to introduce an option for createEpicMiddleware called createDependencies which must be a function that accepts the state$ and returns the actual dependencies (the same dependencies that you'd pass to the dependencies option). This would avoid repeating code, as we wouldn't need manually to pass the state$ to every single dependency.

    If you like this change and will consider merging it, I suggest that we discuss whether or not action$ should be passed too. I believe that it shouldn't, because I can't find any use cases for it, and might enable some anti-patterns. However, if there are legitimate use cases for it, implementing it in the future would break backward compatibility. So I think that this is an important discussion to have.

    By the way, I regret that I committed these changes before realizing that #598 exists. I tried to search for this exact feature but couldn't find it. In this comment you mention an alternative, but I think that the code example is hard to understand and honestly it feels a bit "hacky". I haven't tried it, but in TypeScript, it seems to me that we'd have to either use any or define some complex types.

    If you need some examples of use cases, you can take a look at the commit f4dd2e042c1dcd579b738484d9f7d358bef782a5.

    Thanks for your attention.

    opened by MeLlamoPablo 1
Owner
redux-observable
RxJS middleware for Redux
redux-observable
Thunk middleware for Redux

Redux Thunk Thunk middleware for Redux. npm install redux-thunk yarn add redux-thunk Note on 2.x Update Most tutorials today assume that you're using

Redux 16.6k Sep 23, 2021
:recycle: higher order reducer to add undo/redo functionality to redux state containers

redux undo/redo simple undo/redo functionality for redux state containers Protip: Check out the todos-with-undo example or the redux-undo-boilerplate

Daniel Bugl 2.7k Sep 15, 2021
RxJS middleware for action side effects in Redux using "Epics"

RxJS-based middleware for Redux. Compose and cancel async actions to create side effects and more. https://redux-observable.js.org Install This has pe

redux-observable 7.7k Sep 15, 2021
Logger for Redux

Logger for Redux Now maintained by LogRocket! LogRocket is a production Redux logging tool that lets you replay problems as if they happened in your o

null 5.6k Sep 21, 2021
Ruthlessly simple bindings to keep react-router and redux in sync

Project Deprecated This project is no longer maintained. For your Redux <-> Router syncing needs with React Router 4+, please see one of these librari

React Community 7.9k Sep 20, 2021
A Higher Order Component using react-redux to keep form state in a Redux store

redux-form You build great forms, but do you know HOW users use your forms? Find out with Form Nerd! Professional analytics from the creator of Redux

Redux Form 12.6k Sep 15, 2021
persist and rehydrate a redux store

Redux Persist Persist and rehydrate a redux store. v6 upgrade Web: no breaking changes React Native: Users must now explicitly pass their storage engi

Zack Story 11.6k Sep 21, 2021
Redux DevTools remotely.

Remote Redux DevTools Use Redux DevTools remotely for React Native, hybrid, desktop and server side Redux apps. Installation npm install --save-dev re

Mihail Diordiev 1.8k Sep 16, 2021
Analytics middleware for Redux

redux-analytics Analytics middleware for Redux. $ npm install --save redux-analytics Want to customise your metadata further? Check out redux-tap. Usa

Mark Dalgleish 490 Aug 17, 2021
Redux bindings for client-side search

redux-search Higher-order Redux library for searching collections of objects. Search algorithms powered by js-worker-search. Check out the live demo a

Brian Vaughn 1.4k Sep 10, 2021
redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.js state.

redux-immutable redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.js state. When Redux creat

Gajus Kuizinas 1.9k Sep 7, 2021
A mock store for testing Redux async action creators and middleware.

redux-mock-store A mock store for testing Redux async action creators and middleware. The mock store will create an array of dispatched actions which

Redux 2.4k Sep 21, 2021
Selector library for Redux

Reselect Simple “selector” library for Redux (and others) inspired by getters in NuclearJS, subscriptions in re-frame and this proposal from speedskat

Redux 18.2k Sep 15, 2021
The official, opinionated, batteries-included toolset for efficient Redux development

Redux Toolkit The official, opinionated, batteries-included toolset for efficient Redux development (Formerly known as "Redux Starter Kit") Installati

Redux 6.3k Sep 23, 2021
Official React bindings for Redux

React Redux Official React bindings for Redux. Performant and flexible. Installation Using Create React App The recommended way to start new apps with

Redux 21.4k Sep 23, 2021
An i18n solution for React/Redux and React Native projects

redux-react-i18n An i18n solution with plural forms support for Redux/React Workers of all countries, unite! Supported languages list with expected co

Dmitry Erzunov 64 Aug 9, 2021
The ultimate React SSR, Redux-powered example.

Redux server-side The ultimate React SSR, Redux-powered example. But why? Does any of the following sentences describe your SSR adventures? You'd love

Rafał Krupiński 3 Aug 20, 2021
DevTools for Redux with hot reloading, action replay, and customizable UI

Redux DevTools Developer Tools to power-up Redux development workflow or any other architecture which handles the state change (see integrations). It

Redux 12.1k Sep 21, 2021
DevTools for Redux with hot reloading, action replay, and customizable UI

Redux DevTools Developer Tools to power-up Redux development workflow or any other architecture which handles the state change (see integrations). It

Redux 12.1k Sep 23, 2021