Reactive apps with React + RxJs + TypeScript
Tags: react, rxjs, typescript, functional
Published: 2021-05-05 23:02:39

A modern way to develop web apps.

# Reducing complexity using Redux... or not

When I started to learn React I often heard a lot of [Redux](https://redux.js.org/), the storage concepts, reducers and the stuff related with Redux pattern. I'm such fan and advocate of the design patterns, I was so excited to setup a React app with Redux.

Finally, the day arrived and I needed to setup Redux on my first React app and... I was no such fan of it.

Yes, it's true, Redux makes our React application follow a scalable and maintanable way for our app state management, but at the same time, it’s a tedious way to add new features because you need to add a lot of code: define an action, create a dispatcher, create a reducer, etc.

I used Redux a few times. Obviously, I prefer to use Redux instead to use nothing in our state management application. I know that there's a lot of Redux alternatives, like MobX (I'll talk more about it in a moment) or [GraphQL](https://graphql.org/) (which I like a lot, but maybe you need to plan a very complex architecture, schemas and queries).

I was looking for something simple but powerful. Interestingly, what I was looking for was in Angular. I mean, not the Angular framework itself but a library that is commonly used in Angular applications: RxJS.

# Stop thinking in a static data store, start thinking in data streams instead

In 2017, [ThoughtWorks](https://www.thoughtworks.com/de/radar/languages-and-frameworks/reactivex) recommended to adopt ReactiveX on its [technology radar](https://www.thoughtworks.com/radar).

> “Distributed systems often utilize multithreading, event-based communication and nonblocking I/O to improve the overall system efficiency. These programming techniques impose challenges such as low-level threading, synchronization, thread safety, concurrent data structures, and non-blocking I/O. The open source [ReactiveX](http://reactivex.io/) library beautifully abstracts away these concerns, provides the required application plumbing, and extends the [observable pattern](https://en.wikipedia.org/wiki/Observer_pattern) on streams of asynchronous events. ReactiveX also has an active developer community and supports a growing list of languages, the most recent addition being [RxSwift](https://github.com/ReactiveX/RxSwift). It also implements binding to mobile and desktop platforms.”

I repeat, I’m a big fan of design patterns and ReactiveX implements a pattern very well: *Observables*. Observable pattern is a very interesting pattern and is very useful on most of scenarios. As you could read, iOS Applications uses ReactiveX too. Keep in mind that ReactiveX has a lot of [adaptations for the different programming languages](http://reactivex.io/languages.html). It can be used both in back-end and front-end.

> In a nutshell, there’s a data source that will emit values through time, it will be observed by at least one subscription. The `magic` comes when the data source manipulates the received values asynchronous to obtain more sophisticated or more simple data entities. This is possible due [pipe operators](https://v6.rxjs.dev/guide/v6/pipeable-operators).

[MobX](https://mobx.js.org/README.html) has implemented the Observable pattern too, but in my opinion, the main disavantage of this library is that uses *Object Oriented Programming*. This limiting us a little bit to use Reactive Programming properly.

# React + ReactiveX = A modern and minimalist way to develop apps

Since I learned ReactiveX, I changed the way I develop my applications. I really enjoy to use it. To start with the code stuff, here's an example that I've implemented on my website. 

## Quick view

This is a little bit advanced, so if you don't know much about ReactiveX don't worry, I'll talk in depth later.

```ts
import { Observable, animationFrameScheduler, fromEvent, of } from "rxjs";
import { distinctUntilChanged, filter, map, pairwise, switchMap, throttleTime } from "rxjs/operators";
import { ScrollType, ScrollMovement } from "./types";

export const watchScroll$ = (): Observable<ScrollType> =>
    of(typeof window === "undefined")
        .pipe(
            filter((undefinedWindow) => (!undefinedWindow)),
            switchMap(() => fromEvent(window, "scroll", {passive: true})),
            throttleTime(0, animationFrameScheduler),
            map(() => (window.pageYOffset)),
            pairwise(),
            map(([previous, current]) =>
                (
                    current < previous || current === 0
                        ? ScrollMovement.UP
                        : ScrollMovement.DOWN
                )
            ),
            distinctUntilChanged()
        );
```

What you was just read is a service that provides to me information about the scroll movements of the window. Window object has a lot of information but what I wanted to get was if the user was scrolling up or scrolling down, the purpose of this was enable to shown or hide a nvigation bar on my site. Look the navigation component.

```tsx
import * as React from "react";
import "./Nav.component.scss";
import {useObservable} from "rxjs-hooks";
import {watchScroll$} from "./nav.service";
import {ScrollMovement, ScrollType} from "./types";
// other imports

function Nav(): JSX.Element {
    const scrollDirection: ScrollType = useObservable(watchScroll$, ScrollMovement.UP);

    return (
        <div className={cn("Nav", {"hidden": scrollDirection === ScrollMovement.DOWN})}>
            <div className="Nav__Item">
                <a className="Logo" href="/">
                    <img src={Logo} alt="Carlos Gómez"/>
                </a>
            </div>
            <div className="Nav__Item">
                <Menu/>
            </div>
        </div>
    );
}

export default Nav;
```

Notice that I'm using a custom hook called `useObservable`, you could create your own custom hook but I decided to use this due is factory-based. This hook returns me the last emmited value by `watchScroll$`, then it closes the suscription. This get triggered every render. I just adding the `hidden` class to my div if the user is scrolling up, if not, that class will be removed.

# But, how does ReactiveX work?

Let's get started with the basics. 

1. Create a data source.
By convention, an observable variable uses `$` at it's name.

```ts
import { from } for "rxjs";

const mySource$: Observable<number> = from([1, 2, 3, 4, 5]);
```

In this case I'm using `from` function. This creates an observable with the given params, there's a few methods that RxJS provides to create Observables like `of` or `fromEvent`. At this point this observable do nothing because I don't have suscriptors associate it. Remember that an observable needs at least one suscriptor to start to work.

2. Create a suscription.
Suscription method will listed every value that the source emit. 

```ts
import { from } for "rxjs";

const mySource$: Observable<number> = from([1, 2, 3, 4, 5]);

mySource$.subscribe();
```

At this moment the Observable already started to emit the values but we can't see it or manipulate them because I don't passing any observer at the suscription. The [RxJS Observer](http://reactivex.io/rxjs/class/es6/MiscJSDoc.js~ObserverDoc.html) is an object like:

```ts
interface Observer<T> {
  closed?: boolean;
  next: (value: T) => void;
  error: (err: any) => void;
  complete: () => void;
}
```

So we can pass something like this at the `suscribe()` method.

```ts
import { from } for "rxjs";

const mySource$: Observable<number> = from([1, 2, 3, 4, 5]);

mySource$.subscribe({
  next: (value) => console.log("Next: " ,value),
  error: (error) => console.error(error),
  complete: () => console.log("Observable is completed")
});
```

This finally will show us at the console the values that the observable emitted:
```log
Next: 1
Next: 2
Next: 3
Next: 4
Next: 5
```
But, Observer has a few things that I don't want to touch in this article like `error` and `complete`. So, with practical purposes I will simplify it a little bit:

```ts
import { from } for "rxjs";

const mySource$: Observable<number> = from([1, 2, 3, 4, 5]);

mySource$.subscribe((next) => console.log(next));
```

This works same as before.

3. Add pipe operators.
So, at this moment we have a very basic observable that isn't useful. How about if we add a little bit of complexity to this excercise. An Observable could be emit values of any types, can emit `Objects`, `numbers`, `strings`, `JSX.Elements`, more `Observables`, etc. So imagine that the back-end developer sent me a list of tasks.

```ts
import { Observable, of } from "rxjs";

interface Task {
    name: string;
    id: number;
    completed: boolean;
}

// Imagine this comes from the back-end
const tasks: Task[] = [
    {
        name: "Cleanup and prune system",
        id: 1,
        completed: false
    },
    {
        name: "Daily backup",
        id: 2,
        completed: true
    },
    {
        name: "Execute security scripts",
        id: 3,
        completed: false
    }
];

const tasks$: Observable<Task[]> = of(...tasks);

tasks$.subscribe((nextTasks) => console.log(nextTasks));
```

Output
```log
  {
    name: "Cleanup and prune system"
    id: 1,
    completed: false
  }
  {
    name: "Daily backup",
    id: 2,
    completed: true
  }
  {
    name: "Execute security scripts",
    id: 3,
    completed: false
  }
```

## What is a pipe operator?
> Pipe operator is like a tweak that manipulates the observable input and returns another. 

This time I want to recover only the pending tasks. For that I will use the pipe operator `reduce` that works same as `Array.reduce()`.

```ts
import { Observable, of } from "rxjs";
import { reduce } from "rxjs/operators";

interface Task {
    name: string;
    id: number;
    completed: boolean;
}

// Imagine this comes from the back-end
const tasks: Task[] = [
    {
        name: "Cleanup and prune system",
        id: 1,
        completed: false
    },
    {
        name: "Daily backup",
        id: 2,
        completed: true
    },
    {
        name: "Execute security scripts",
        id: 3,
        completed: false
    }
];

const tasks$: Observable<Task[]> =
    of(...tasks)
        .pipe(
            reduce<Task, Task[]>((pendingTasks, nextTask) => (
                !nextTask.completed
                    ? [...pendingTasks, nextTask]
                    : pendingTasks
            ), [])
        );


tasks$.subscribe((nextTasks) => console.log(nextTasks));
```


Output
```log
[
  {
    name: "Cleanup and prune system"
    id: 1,
    completed: false
  },
  {
    name: "Execute security scripts",
    id: 3,
    completed: false
  }
]
```

Great! That's a better approach. Now, imagine that the back-end developer adds a new feature to the tasks: `priority`, then we need to `filter` the pending tasks by high priority only, so I added a functionality using `filter` operator.

```ts
import { Observable, of } from "rxjs";
import { filter, reduce } from "rxjs/operators";

interface Task {
    name: string;
    id: number;
    completed: boolean;
    priority: Priority;
}

enum Priority {
    HIGH,
    MEDIUM,
    LOW
}

// Imagine this comes from the back-end
const tasks: Task[] = [
    {
        name: "Cleanup and prune system",
        id: 1,
        completed: false,
        priority: Priority.LOW
    },
    {
        name: "Daily backup",
        id: 2,
        completed: true,
        priority: Priority.HIGH
    },
    {
        name: "Execute security scripts",
        id: 3,
        completed: false,
        priority: Priority.MEDIUM
    },
    {
        name: "Verify tests",
        id: 4,
        completed: false,
        priority: Priority.HIGH
    }
];

const tasks$: Observable<Task[]> =
    of(...tasks)
        .pipe(
            filter((task) => (task.priority === Priority.HIGH)),
            reduce<Task, Task[]>((pendingTasks, nextTask) => (
                !nextTask.completed
                    ? [...pendingTasks, nextTask]
                    : pendingTasks
            ), [])
        );


tasks$.subscribe((nextTasks) => console.log(nextTasks));
```

The `pipe` method could chain mutiple operators, it follows the order of the operators. In this case I decided to filter first, then, with the filtered values I'm creating a list of unfinished tasks. I could chain the number of operators as I need.

Output
```log
[
  {
    name; "Verify tests",
    id: 4,
    completed: false
  }
]
```

# Real-world example (Progress Bar)
I hope you find useful the brief introduction of RxJS. I shown a couple of RxJS examples but I want to show the full path of React + RxJS with simple but powerful implementation. Let's create a simple `Progress Bar`.

For this implementarion I'll just need three things:
  1. A React component.
  2. A service which observe the state of the window
  3. A SCSS file.

First, the Observable and service. I need a data source, so, I'm using `fromEvent` which will observe the `document's scroll` in this case.

```ts
import {fromEvent} from "rxjs";

const scroll$ = fromEvent(document, "scroll");
```

I need to manipulate that values to return a number, so, I created another Observable called `progress$`. The `scroll$` observable is returning an `Event`, so I will analyze that `Event` with the `map` operator. Inside the map I'm just calculating the percentage of the user progress at the document.

```ts
import {fromEvent, Observable} from "rxjs";
import {map} from "rxjs/operators";

const scroll$ = fromEvent(document, "scroll");

export const progress$ = (): Observable<number> => scroll$
    .pipe(
        map(
          (event) => {
            const {scrollTop, scrollHeight, clientHeight} = (event.target as Document)?.documentElement;
            return (scrollTop / (scrollHeight - clientHeight)) * 100;
          }
        )
    );
```

When I scroll, the output will be recalculated and he result is a number between `1` and `100`. Great! That's what I wanted. Next step: The React component.

```ts
import * as React from "react";
import "./ProgressBar.component.scss";
import { useObservable } from "rxjs-hooks";
import { progress$ } from "./progressBar.service";

export default ProgressBar;

function ProgressBar(): JSX.Element {

    const progress = useObservable(progress$, 0);

    return (
        <div className="ProgressBar" style={{width: `${progress}%`}/>
    );
}
```

Notice that I'm using again the custom `useObservable` hook to subscribe and get the last value of `progress$`. This seems good, the last step is to add the styles.


```ts
.ProgressBar {
  position: fixed;
  bottom: 0;
  left: 0;
  height: 0.3em;
  background: red;
  transition: width;
}
```

That simple. No actions, no reducers, just Observables. You see it?

# Last thoughts
State managment is a primordial topic on an application. Using ReactiveX on React applications changed my vision and how to develop my apps in a modern way, functional and reactive. I think that every React developer needs to give a chance to RxJS and maybe, just maybe, avoid Redux. Thanks for reading.