React-Redux apps on Rx steroids
Tags: react, redux, rxjs
Published: 2020-07-05 19:47:18

Since 2014 almost every week I've heard something about Rx. I've read many Rx docs, articles, and code examples. But I still had no idea why I should move to reactive programming paradigm if I can successfully solve my tasks with `element.addEventListener(…)`.

In 2020 I found an awesome way to make complex react-redux components dumb and testable with Rx. And I'd like to share it with you in this article.

_This article doesn't include Rx basics. If need you may find it [here](https://rxjs.dev/guide/overview)._

To see the Rx power let's start with an example.

Imagine there is a website that lists famous quotes. This website's users may do the following things:
- read quotes
- mark a quote as favorite

And this website may look like on the image below.

![website mockup](https://dev-to-uploads.s3.amazonaws.com/i/sqbfwf2bd50uolsqpmbn.png)

As you may see this webpage highlight favorite quotes for signed-in users only. So this website also has a sign in popup.

![website sign in popup mockup](https://dev-to-uploads.s3.amazonaws.com/i/lbtc207d2ringysgkupc.png)

So now we imagine a component connected to redux that has quotes list, user data, and favorite quotes ids. And it makes a request to get favorite quotes list when a user is signed in.

```javascript
class QuotesComponent extends React.Component {
  componentDidUpdate(prevProps) {
    const {user} = this.props

    if (undefiend === prevProps.user && undefined !== user) {
      dispatch(loadFavorites(user.id))
    }
  }

  // other methods
}
```

With current realization, this component knows not only about things to render. This component also contains some logic to make requests at the right moment.

And Rx comes here.

[redux-observable](https://redux-observable.js.org/) is an awesome library that allows you to work with redux actions and state like with a stream. The core primitive to do that is [Epic](https://redux-observable.js.org/docs/basics/Epics.html).

To make the `QuotesComponent` simpler we will do the following steps: 

1. replace the `componentDidUpdate` implementation with `componentDidMount`
1. create an epic to load favorite quotes ids for a user

With redux-observable we don't need to track the user prop more. So we may just enqueue favorites loading in `componentDidMount`:

```javascript
class QuotesComponent extends React.Component {
  componentDidMount() {
    dispatch(enqueueLoadFavorites())
  }

  // other methods
}
```

Why we don't need to track the user prop? Because we will create an epic that will do that for us.

```javascript
const enqueueLoadFavoritesEpic = (action$, state$) => action$.pipe(
  filter(action => action.type === 'enqueueLoadFavorites'),
  switchMap(() => {
    const user = selectUser(state$.value)

    if (undefined === user) {
      // wait for signing in before loading favorites

      return state$.pipe(
        map(state => selectUser(state)),
        filter(user => user !== undefined)
        take(1),
        switchMap(() => {
          return of(loadFavorites(user.id))
        }),
      )
    }

    return of(loadFavorites(user.id))
  }),
)

const loadFavoritesEpic = () => {
  // do some async work, requests, get data and dispatch result action
}
```

The `enqueueLoadFavoritesEpic` doing the following steps:

1. wait for enqueue action
1. check for signed-in user

   - dispatch load action if a user is signed in
   - create a store observer that waits for a signed-in user to dispatch load action

Well as you see redux-observable is a great tool to handle pending actions depends on the store. redux-observable makes your components dumb and gets a way to test pending actions with unit tests.