React Data Fetching
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:
- Size
- Typescript
- Active Community/Support
To the cloud! After searching reddit r/reactjs
for 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
Stats
First, let's look at the stats at the date of writing this post:
Github
Github | Contributors | Issues | Last change | Stars |
---|---|---|---|---|
React Query | 36 | 1 | 15 hours | 4k |
Rest Hooks | 17 | 9 | 2 days | 924 |
SWR | 42 | 52 | 5 days | 7.3k |
React Async | 21 | 20 | 18 Hours | 1.7k |
npm
npm | Version | Weekly | Published | Size |
---|---|---|---|---|
React Query | 1.0.7 | 10,583 | 16 hours | 357kb |
Rest Hooks | 4.5.2 | 2,871 | 3 days | 725kb |
SWR | 0.1.18 | 31,103 | 5 days | 76.7kb |
React Async | 10.0.0 | 15,637 | 3 months | 337kb |
SWR wins on stats it's the smallest and most popular of the bunch.
Playtime
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.
React Query
Installation
Simple install then straight into sample code, looks simple enough will try fetching my top level, Story model.
Usage
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.
Mutations
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
Rest Hooks
Installation
- Babel config
- Add Cache Provider
- Add Suspense and ErrorBoundary
Usage
- 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 /backlog/{id}/stories
.
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 ๐
SWR
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.
Installation
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
happen.
- Child data working first time too, so far so good. On to mutation!
Mutations
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!
- Small
- Typescript working out of the box
- Refresh on re-focus
- Suspense support
- Popular
React Async
Installation & usage
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 ๐
Conclusion
SWR wins for me, it easily meets my criteria of:
- Size
- Typescript
- 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?
Top comments (6)
Hey Justin, I would like to point out that in terms of size comparison please do use services like bundle-phobia.
Why would you compare the repository sizes then say that SWR at least in the size comparison. Gzipped react-query has 6.2kb, while SWR has 6.1kb. Basically the same.
I can't comment on the rest, but this particular issue really irked me as you mentioned a few times the miraculous size of SWR :)
Hey Constantin, bundle-phobia looks like a great site thanks. I was going purely off the sizes reported on npmjs.com, react-query is currently reporting as 702 kB.
I've been meaning to post a follow-up about react-query, I'm now using it instead of SWR. The react-query dev tools are awesome!
Understanble, but what's reported on npm is the package size, not the bundle size. :)
I really liked thisโI had only heard of React Query. I'm going to try SWR on a project right now, I'm a huge fan of the projects Vercel works on. Have you had any problems with SWR?
Hey Tyler, I'm also a big Vercel fan (next.js!) and I've not found any problems with SWR but... I'm now using React Query and find its Dev Tools to be a real game changer, being able to easily dig into the data during development is so useful.
I'd say give SWR a try and see what you think, its a great tool :-)
Thanks for the insights!