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 ⭐️