In the previous post on Recks, we used axios Promises to query github API:
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 to Observable-based axios-observable (a wrapper around the former):
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:
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!
catchError(() => of(<i>Error!</i>))
catchError
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" for details!
Flickering
Well, this is a bit harder. We'll need a whole 3 more lines:
zip(
axiosObservable.request(url),
timer(500),
x => x
)
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.
All together
Let's recap what we've written:
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
The source code is available at github.com/recksjs/recks
The end
header photo by Mitchell Orr on Unsplash
Top comments (2)
logic and request in the template? ๐คฎ๐คข
Hi, Tiago! Thank you for the comment ๐
Well, since JSX is a structure of objects, React allows you to do pretty much any wild stuff in their templates too! ๐คฏ
The given example was rather supposed to show that any child could be a stream, which gives us so many powers! (partially described above)
Would it look cleaner if we moved the request logic to a function? E.g.:
And the engine is flexible, so we can
map
the whole request result to a JSX(this one looks more reactish, imho)
Again, with the article examples, I wanted to show the idea of manipulating streams on a level, native to the framework. And I agree that they might not reflect best practices ๐
Hope, my clumsy examples won't hide an interesting concept behind them โญ๏ธ