🐶 Truly reactive! Rx+JSX experiment
Tags: rxjs, javascript, react, webdev
Published: 2019-12-12 16:48:47

In the previous post on [Recks](https://github.com/recksjs/recks), we [used axios Promises](https://dev.to/kosich/rx-jsx-experiment-promises-in-recks-3585) to query github API:

```jsx
import axios from 'axios';

function App() {
  const url = 'https://api.github.com/repos/axios/axios';

  return <div>
    <h1>Axios</h1>
    <p>{
      axios.get(url).then(response => response.data.description)
    }</p>
  </div>
}
```
<figcaption><a href="https://codesandbox.io/s/recks-example-promises-w1uvv?fontsize=14&hidenavigation=1&theme=dark&module=/src/App">online sandbox</a></figcaption>

In this post, we'll improve our application UX by:

- adding a loading indicator
- displaying an error if such occurs
- and we'll avoid flickering on fast connections

## Preparation

First, let's move from Promise-based [axios](https://github.com/axios/axios) to Observable-based [axios-observable](https://github.com/zhaosiyang/axios-observable) (a wrapper around the former):

```jsx
import axiosObservable from 'axios-observable';

function App() {
  const url = 'https://api.github.com/repos/ReactiveX/rxjs';

  return <div>
    <h1>RxJS</h1>
    <p>{
      axiosObservable.get(url).pipe(
        map(response => response.data.description)
      )
    }</p>
  </div>
}
```

The behavior stays the same: what `.then` did in Promises, now is handled by RxJS `map`.

**With Observables supporting our might, we are good to create Wonders!**

_N.B.: There's a hidden benefit here! Apart from tons of operators available in RxJS, we also get a request cancelation on component un-mount **for free!**_

## Loading indicator

To show a loading indicator before the response is loaded — we simply need to emit it first:

```jsx
  startWith(<span>Loading...</span>)
```

`startWith` operator will emit the given value and after that will proceed with the rest of the events. In our case — we emit a `<span/>` element. Next value on the stream will substitute it.

Done!

## Error handling

Guess what? Rx has an operator for that too!

```jsx
  catchError(() => of(<i>Error!</i>))
```

[`catchError`](https://thinkrx.io/rxjs/catch/) operator will substitute an error event on the stream with another stream. In our case — we'll emit an `<i/>` if an error is thrown.

Done!

_Psst! Hey, want some retry-on-error operators? Or you wanna learn a fancy retry-with-delay technique? Check out my article ["Error handling in RxJS"](https://medium.com/@kddsky/error-handling-in-rxjs-bac0f96a7def) for details!_

## Flickering

Well, this is a bit harder. We'll need a whole 3 more lines:

```jsx
zip(
  axiosObservable.request(url),
  timer(500),
  x => x
)
```

[zip](https://thinkrx.io/rxjs/zip/) will wait for `axios.request` and `timer(500)` both to emit a value and then will produce a combined result. `x=>x` function is needed to ignore value emitted by the timer and take only the axios response.

![Elzar from Futurama](https://thepracticaldev.s3.amazonaws.com/i/fcci4dsokbpogfgyeypq.png)

<figcaption>BAAM!<br/>Don't you worry, Elzar knows what to do with a spice weasel. <b>It won't be cooked!</b></figcaption>

## All together

Let's recap what we've written:

```jsx
function App() {
  const url = 'https://api.github.com/repos/ReactiveX/rxjs';

  return <div>
    <h1>RxJS</h1>
    <p>{
      zip(
        axiosObservable.get(url),
        timer(500),
        x => x
      ).pipe(
        map(response => response.data.description),
        startWith(<span>Loading...</span>),
        catchError(() => of(<i>Error!</i>))
      )
    }</p>
  </div>
}
```

<figcaption><a href="https://codesandbox.io/s/recks-example-http-request-z9wgb?fontsize=14&hidenavigation=1&theme=dark&module=/src/App">online sandbox</a></figcaption>

Wasn't that easy?!

Here are the benefits we achieved:

⭐️ loading indication, error handling, anti-flickering in a minute
⭐️ in-place updates with no state
⭐️ automatic request abortion on unmount
⭐️ great extensibility with dozens of RxJS operators 🚀

Share your thoughts in the comments!

## To try Recks 🐶

Clone the template repository:

```
git clone --depth=1 https://github.com/recksjs/recks-starter-project.git
cd recks-starter-project
npm i
npm start
```

Or use this [online sandbox](https://codesandbox.io/s/recks-example-greeting-input-tu6tp?fontsize=14&hidenavigation=1&theme=dark)

The source code is available at [github.com/recksjs/recks](https://github.com/recksjs/recks)

## The end

_header photo by [Mitchell Orr](https://unsplash.com/@mitchorr?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)_