Using React and RxJS together
Tags: rxjs, react, javascript, frontend
Published: 2020-06-03 13:21:56

---
title: Using React and RxJS together
published: true
description: Moving effect handling from React to RxJS
tags: rxjs, react, javascript, frontend
cover_image: https://images.unsplash.com/photo-1519889162496-9e3f406fa199?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2689&q=80
---

_Cover image by [Wu Yi on splash](https://unsplash.com/@takeshi2)._

This article was originally posted on Spanish [in my blog](https://daslaf.dev/posts/react-y-rxjs/)

> This article is not a tutorial about React nor about RxJS, but just some of my thoughts about how to use RxJS on React applications.

RxJS is a library for Functional Reactive Programming (FRP from now on) in JavaScript. If you google what is **FRP**, you'll probably find a lot of really _cool_ definitions, each one a little bit more complex than the previous one.

My favorite definition of **FRP** is:

> The essence of FRP is to specify the dynamic behavior of a value when declaring it
> – Heinrich Apfelmus

Mind-blowing right?

**What does this mean?**

When doing **FRP** we try to specify how the value of a variable is going to change over time at declaration time. It might seem rather strange how code like this would look, since JavaScript doesn't have primitives for doing something like this (generators is the closest thing I can think of).

On React land there IS a way to define the value of a variable that _could_ satisfy this definition, but with some limitations. Consider the following example:

```javascript
const greeting = React.useMemo(() => `${greet}, ${name}!`, [greet, name]);
```

`useMemo` lets us define a computed value that will be recalculated whenever their dependencies change. In our case, the value of `greeting` will be recomputed depending on the values of `greet` and `name`. Fair enough, `greeting` is just the result of a simple expression `` `${greet}, ${name}!` ``, but it turns out we control when its value is recomputed by using `useMemo`, which is convenient for our definition of reactivity.

Wonderful! And that could be all, folks, and we'd live happily ever after. However, `useMemo` only lets us define `greeting` when `greet` and `name` change, but it doesn't provide any information about where and how those values change and how they are updated. 

The million dollar question is: How and where do these dependencies change?

Looking at a more realistic example:

```javascript
import * as React from 'react';

const GreetSomeone = ({ greet = 'Hello' }) => {
    const [name, setName] = React.useState('World');
    const greeting = React.useMemo(() => `${greet}, ${name}!`, [greet, name]);

    React.useEffect(() => {
        fetchSomeName().then(name => {
            setName(name);
        }, () => {
            setName('Mololongo');
        });
    }, []);

    return <p>{greeting}</p>;
};
```

Out `GreetSomeone` component receives `greet` from `props` and `name` is the result of a promise returned by calling `fetchSomeName`.

Although the definition of `greeting` hasn't changed, we cannot determine just by reading it that one of the values on the dependency array comes from a Promise and that by extent, is async.

In JavaScript there are no primitives for determining the async nature of this expression (neither in React).

## Observables to the rescue

Let's get away from React for a while and let's see if we can express `greeting` (and fulfill our FRP definition) using RxJS. We'll start by defining two Observables that will emit the values of `greet` and `name`, and we will compose them to get another Observable back that will represent how `greeting` changes over time:

```javascript
import { combineLatest, of } from 'rxjs';
import { map } from 'rxjs/operators';

const greet$ = of('Hello');
const name$ = of('World');

const greeting$ = combineLatest(greet$, name$).pipe(
    map(([greet, name]) => `${greet}, ${name}!`)
);

greeting$.subscribe(greeting => {
    console.log(greeting);    
});

// =>: "Hello, World!" -- When we subscribe to greeting$
```

In our React example the value of `name` came from a Promise. In RxJS land, defining the async nature of `name` is quite simple, we only have to create an Observable _from_ `fetchSomeName` and handle weather the Promise is resolved or rejected in the following way:

```javascript
import { combineLatest, from, of } from 'rxjs';
import { catchError, map, startWith } from 'rxjs/operators';

const greet$ = of('Hello');
const name$ = from(fetchSomeName()).pipe(
    startWith('World'),
    catchError(() => of('Mololongo')),
);

const greeting$ = combineLatest(greet$, name$).pipe(
    map(([greet, name]) => `${greet}, ${name}!`)
);

greeting$.subscribe(greeting => {
    console.log(greeting);    
});

// ✏️: "Hello, World!"      -- When we subscribe to greeting$
// ✅: "Hello, Thundercat!" -- When `fetchSomeName()` is resolved
// ❌: "Hello, Mololongo!"  -- When `fetchSomeName()` is rejected
```

And that is all it take to define the async nature of `name$` and by extent, the async nature of `greeting$`.

## Back to React

Considering what we know so far. How we could implement our RxJS solution in React?

To answer this question, it's convenient to first understand that `useMemo` is kind of equivalent to `useState` + `useEffect`. For example:

```javascript
const greeting = React.useMemo(() => `${greet}, ${name}!`, [greet, name]);
```

Can be described like:

```javascript
const [greeting, setGreeting] = useState(() => `${greet}, ${name}!`);

useEffect(() => {
    setGreeting(() => `${greet}, ${name}!`);
}, [greet, name]);
```

Although in practice both _snippets_ yield similar results, there are a couple of substantial differences on how they do it.

The callback function we pass to `useEffect` runs **after** render, while the `useMemo` variable is calculated **before** render. In other words, during the first render the value of `greeting` with `useMemo` will already be computed; whilst in our `useEffect` version, its value on the first render will be the value defined with our `useState`.

The fact we can describe a state update inside a `useEffect` callback, is just pointing out that updating state is in practice a "side effect", as in it is affecting _the real world_. In the case of `useMemo`, this is conveniently handled by React.

With that being said, the strategy to use RxJS with React is basically by **deferring the way we handle these (side) effects** from React to RxJS.

We'll start by copying all of our RxJS code inside our `GreetSomeone` component. In order to render our component whenever `greeting$` emits a value, we have to let React know that something happened by using some mechanism familiar to React, like `useState`:

```javascript
import * as React from 'react';
import { combineLatest, from, of } from 'rxjs';
import { catchError, map, startWith } from 'rxjs/operators';

const GreetSomeone = ({ greet = 'Hello' }) => {
    const [greeting, setGreeting] = React.useState('');

    React.useEffect(() => {
        const greet$ = of(greet);
        const name$ = from(fetchSomeName()).pipe(
            startWith('World'),
            catchError(() => of('Mololongo')),
        );

        const greeting$ = combineLatest(greet$, name$).pipe(
            map(([greet, name]) => `${greet}, ${name}!`)
        );

        const subscription = greeting$.subscribe(value => {
            setGreeting(value);
        });

        return () => {
            subscription.unsubscribe();
        }
    }, []);

    return <p>{greeting}</p>;
};
```

After the first render (when the component "mounts"), the function we passed to `useEffect` will be executed, and with that all the logic to calculate the value of `greeting`.

One problem with our current solution is that if the of value of `greet` changes, `greeting` will not be recomputed. This is because our `greet$` Observable is defined when the `useEffect` callback is executed, and this just happens once. Any change to `greet` will not be propagated to `greet$`, and by extension neither `greeting$` will know about it.

One thing we could do is add `greet` as a dependency to `useEffect`, making sure that the callback is executed every time `greet` changes. Although this solves our problem, it could have some unexpected consequences.

The effect callback will be executed EVERY time `greet` changes. When the callback runs, not only we will be defining `greet$` with the latest value `greet`, but also `name$` will be redefined, and this will execute the `getSomeName` function again. 

In our initial example we are only interested in calling `getSomeName` once, so let's forget about this alternative.

Something interesting about the dependency array of React hooks: The hook callback will be executed only when its dependencies change, and React tracks these changes by just doing plain old value comparison. In JavaScript, primitive values are equal when their values are equal (`5` is always equal to `5`) but things like objects are only equal if they point to the same reference (memory address, call it whatever you like).

What this actually means is that if we have an object as a dependency, and the reference to that object doesn't change, it doesn't matter how the inner properties of that object change: the hook simply will not be executed. It will only run when the variable we are observing points to a different reference.

What we'll do then, is define `greet$` as a `BehaviorSubject` (using a ref) that will emit values whenever `greet` changes:

```javascript
import * as React from 'react';
import { BehaviorSubject, combineLatest, from, of } from 'rxjs';
import { catchError, map, startWith } from 'rxjs/operators';

const GreetSomeone = ({ greet = 'Hello' }) => {
    const greet$ = React.useRef(new BehaviorSubject(greet));

    // Observe `greet` with `useEffect` and forward the value to `greet$`
    React.useEffect(() => {
        greet$.current.next(greet);
    }, [greet]);

    // Rest of the code remains almost the same
    const [greeting, setGreeting] = React.useState('');

    React.useEffect(() => {
        const name$ = from(fetchSomeName()).pipe(
            startWith('World'),
            catchError(() => of('Mololongo')),
        );

        const greeting$ = combineLatest(greet$.current, name$).pipe(
            map(([greet, name]) => `${greet}, ${name}!`)
        );

        const subscription = greeting$.subscribe(value => {
            setGreeting(value);
        });

        return () => {
            subscription.unsubscribe();
        }
    }, [greet$]);

    return <p>{greeting}</p>;
};
```

`BehaviorSubject` is kinda like an event emitter which we can subscribe to (just like we do with regular Observables), but as with any event emitter, we con produce values imperatively calling the `next` method. We store our subject with `useRef`, which lets us persist our reference between _renders_.

But how this is better if we have more code?

First, our main `useEffect` callback just runs once: Hooray!

Second, we can hide the implementation details using a custom hook:

```javascript
const useObservedValue = value => {
    const subject = React.useRef(new BehaviorSubject(value));

    React.useEffect(() => {
        subject.current.next(value);
    }, [value]);

    return React.useMemo(() => subject.current.asObservable(), [subject]);
};
```

And then:

```javascript
const GreetSomeone = ({ greet = 'Hello' }) => {
    const greet$ = useObservedValue(greet);
    const [greeting, setGreeting] = React.useState('');

    React.useEffect(() => { /* etc */ }, [greet$]);

    return <p>{greeting}</p>;
};
```

> `useObservedValue` returns the memoized value of `subject.current.asObservable()` to discourage emitting values manually on our Subject using `next`.

Continuing with our refactoring, we can extract the definition of `name$` from the `useEffect` callback (we can actually extract it from out component entirely, FWIW).

We'll also define `greeting$` outside of `useEffect`:

```javascript
import * as React from 'react';
import { from, of } from 'rxjs';
import { catchError, map, startWith } from 'rxjs/operators';

const name$ = from(fetchSomeName()).pipe(
    startWith('World'),
    catchError(() => of('Mololongo')),
);

const GreetSomeone = ({ greet = 'Hello' }) => {
    const greet$ = useObservedValue(greet);
    const greeting$ = React.useMemo(
        () => combineLatest(greet$, name$).pipe(
            map(([greet, name]) => `${greet}, ${name}!`)
        )), []
    );

    const [greeting, setGreeting] = React.useState('');

    React.useEffect(() => {
        const subscription = greeting$.subscribe(value => {
            setGreeting(value);
        });

        return () => {
            subscription.unsubscribe();
        }
    }, [greeting$]);

    return <p>{greeting}</p>;
};
```

Finally, our `useEffect` only responsibility is to subscribe to  `greeting$` and persist each emitted value with `setGreeting`.

We could even encapsulate this with another custom hook:

```javascript
const useObservable = (observable) => {
    const [value, setValue] = React.useState();

    React.useEffect(() => {
        const subscription = observable.subscribe((v) => {
            setValue(v);
        });

        return () => {
            subscription.unsubscribe();
        };
    }, [observable]);

    return value;
};
```

Finally:

```javascript
import * as React from 'react';
import { from, of } from 'rxjs';
import { catchError, map, startWith } from 'rxjs/operators';

const name$ = from(fetchSomeName()).pipe(
    startWith('World'),
    catchError(() => of('Mololongo')),
);

const GreetSomeone = ({ greet = 'Hello' }) => {
    const greet$ = useObservedValue(greet);
    const greeting$ = React.useMemo(
        () =>
            combineLatest([greet$, name$]).pipe(
                map(([greet, name]) => `${greet}, ${name}!`)
            ),
        [greet$]
    );

    const greeting = useObservable(greeting$);

    return <p>{greeting}</p>;
};
```

And that is it! We've specified the dynamic behavior of `greeting$` at its definition place. You can see a working demo <a href="https://codesandbox.io/s/using-rxjs-observables-inside-react-pjq6n" target="_blank" rel="noopener noreferrer">here</a>.

## Sorting things out

Ok, I get it. The solution I've implemented is not the cleanest and has a lot of rough edges. But, it is a good starting point to understand what it takes to use RxJS Observables in React.

Rather than using our own custom hooks, we could use a library for handling all the boilerplate. Let's take a look at the same example using <a href="https://github.com/LeetCode-OpenSource/rxjs-hooks" target="_blank" rel="noopener noreferrer">rxjs-hooks</a>:

```javascript
import * as React from 'react';
import { from, of } from 'rxjs';
import {
    catchError,
    combineLatest,
    map,
    pluck,
    startWith,
} from 'rxjs/operators';
import { useObservable } from 'rxjs-hooks';

const name$ = from(fetchSomeName()).pipe(
    startWith('World'),
    catchError(() => of('Mololongo'))
);

const GreetSomeone = ({ greet = 'Hello' }) => {
    const greeting = useObservable(
        input$ =>
            input$.pipe(
                pluck(0),
                combineLatest(name$),
                map(([greet, name]) => `${greet}, ${name}!`)
            ),
        '',
        [greet]
    );

    return <p>{greeting}</p>;
};
```

You can look at their documentation to understand what `useObservable` does under the hood. But truth be told, the code surface is considerably reduced.

---

And _voilá_, that's all for today. By using RxJS we can express the async dynamic behavior of our state in a more declarative fashion, by using function composition and other fancy functional programming techniques.

It also lets us define really complex async logic that would be a nightmare to handle using plain old Promises.

Although there is some friction when using RxJS inside React, hooks play a great role in order to improve the way both libraries operate together.

If you liked the content, don't forget to share it on Twitter and follow me over [there](https://twitter.com/daslaf) perhaps.

Beware: I mostly tweet JavaScript rants on Spanish.