I'm looking for a better way to handle data fetching and updating in React, when I say better I mean something more than my current bare bones Axios implementation.
Things that are important to me:
- Active Community/Support
To the cloud! After searching reddit
fetch and picking through the posts I came up with a few libraries that seemed to fit the bill. In no particular order:
- React Query - Hooks for fetching, caching and updating asynchronous data in React
- Rest Hooks - Delightful Data Fetching
- SWR - React Hooks for Remote Data Fetching
- React Async - Flexible promise-based React data loader
First, let's look at the stats at the date of writing this post:
|React Query||36||1||15 hours||4k|
|Rest Hooks||17||9||2 days||924|
|React Async||21||20||18 Hours||1.7k|
|React Query||1.0.7||10,583||16 hours||357kb|
|Rest Hooks||4.5.2||2,871||3 days||725kb|
|React Async||10.0.0||15,637||3 months||337kb|
SWR wins on stats it's the smallest and most popular of the bunch.
I'm going to try each of the libraries for a couple of hours and see how far I can get converting a page over from vanilla Axios calls to use the library. The page I'm trying has a nested data model of a Story with many Tasks and many Comments.
Simple install then straight into sample code, looks simple enough will try fetching my top level, Story model.
PROBLEM - Typescript typings don't seem to work out of the box ☹️
Seems the @types/react-search typings are out of sync with the current version too. Ho hum, I've stuck a global module typing in for now.
declare module 'react-query';
The fetch status returned from
useQuery match exactly the ones I'm using in my vanilla Axios fetcher, handy!
The first call to the backend failed but error handling picked it up nicely, its
also retrying a few times at different intervals 😀 Retry Docs
The page is also auto refreshing when I move away and back to the browser, another plus for react-query 😀
Fixed the query problem and top level Story being returned and cached 😀
Onto the child data...
Works exactly the same as the parent component just run the
useQuery hook in the child components.
As well as queries the library also allows mutations, will try sending some updates...
Updates work but I couldn't get the cache manual update to work. I was hoping to push an updated task into the cache an have it render immediately. Then call a server refresh but I couldn't get that to work. Maybe with a little more time but my few hours are up. It does look like this is worth coming back to revisit.
My couple of hours are up, how was it?
- Very easy to get going, I was querying data with very few changes to my current code base
- Auto refresh was an unexpected surprise
- Query and caching worked well but mutation took more work which is to be expected
- Babel config
- Add Cache Provider
- Add Suspense and ErrorBoundary
- Define a resource
Looks promising my project is using Typescript and already uses typed data models so this should be a good fit.
PROBLEM - Resources need a defined url, the url I use for the Story model is not static 🙃
How do we handle that? My url would have to be
Looks like we can handle this: https://resthooks.io/docs/guides/url
Loading state and error states are handled at a high level on the component tree, or it looks like you can have lower level handlers if you like.
Cool we have top level data returned, now can we get the child data...
No problem with child data we just define Resource models for Tasks and Comments and they work
My couple of hours are up, how was it? Good mostly 'it just worked'.
- Good docs
- Suspense support was nice
- High level Error handling
- Felt opinionated which is not a bad thing as long as you agree with the opinions 😀
The name “SWR” is derived from stale-while-revalidate, a cache invalidation
strategy popularized by HTTP RFC 5861. SWR first returns the data from cache
(stale), then sends the fetch request (revalidate), and finally comes with the
up-to-date data again.
Quick start guide seems simple enough, let's give it a try.
Loading of top level data working first time, either this is an easy to use library or I'm getting better using the libraries 😉
On to the child data... Looks like SWR has us covered here using Dependent Fetching
SWR also allows you to fetch data that depends on other data. It ensures the
maximum possible parallelism (avoiding waterfalls), as well as serial
fetching when a piece of dynamic data is required for the next data fetch to
- Child data working first time too, so far so good. On to mutation!
Got it working after wrestling with React Array item mutations, think I now know how to get the mutations working in react-query 😀
- Suspense support too 😀
How did it go? Really well, there is a lot to like about SWR. No wonder it's so popular!
- Typescript working out of the box
- Refresh on re-focus
- Suspense support
Installation was straight forward, there are 3 different ways to use the library:
React Async offers three primary APIs: the useAsync hook, the
component and the createInstance factory function. Each has its unique
benefits and downsides.
I'll be trying the
useAsync hook as it most closely matches the other libraries but the
Async components look interesting.
Let's try and load the top level data.
PROBLEM Typescript setup was a bit funky, good description on how to get it working here React-Async with TypeScript
Once the TypeScript problem was sorted it was onto loading the child data which was straight forward 😀
Now does it handle mutations? React Async has us covered with optimistic updates
How did it go? The typescript problems at the start slowed me down for a while but it was all go after that.
- Cuts out a lot of the component boilerplate
- The helper components look great
- Suspense support
- No caching 🙃
SWR wins for me, it easily meets my criteria of:
- Active Community
I though its popularity might have been due to its next.js roots but it really stands out on its own. Definitely worth further investigation!
Maybe you have some other favourite?