React Router vs React Query: There Will Be Blood!
Wait a minute! are they antagonists? TLDR: They are not But I like the violent title.
Abstract
I stop by an article from Kent C. Dodds when he was comparing the capabilities from React Router and React Query. Besides, he was making them both to play together. I did find that approach very amusing to try, so here we will explore and combine the data fetching capabilities from React Router while keeping the data caching skills from React Query.
STOP THIS MADNESS AND SHOW ME THE CODE
React Router has Data Fetching APIs
React router V6 besides its new data routers is bringing data fetching concepts to client renderer applications. Because, as expressed by Ryan Florence,
the sooner you fetch the better the user experience.
Well, fetching as early as possible could improve not only the user experience but the developer experience. Since we no longer have to deal with pending and fallback states but spinner components in our UIs. Although this is not a novelty idea, since Server Side Rendering depict this future: having the data available before rendering the component.
Traditional UIs such the ones using React Query follows the below pattern:
As shown by the code we are bound to pending and error states on every page where server data is needed. On top of that, the code is no longer ease to follow and the complexity of managing additional states makes our code to smell.
After a long blank page we get the fallback UI and then the data.
The React Router Proposal: fetch as early as possible.
By the time the component mounts, the data is already there.
Aha! no pending states, no fallback UIs, no error states 😍. And the code for the loader.
Since page transition happens when the data is available, the first route the user hits (when navigating to our application site) will still render a long blank page before anything 🥲.
But subsequent page navigations will state in the current route before data for the next route arrives. That is why, we no longer care about error states or fallback UIs inside React Components.
One downside of this approach is that in Development with React Strict mode enable, React will call the loader and therefore fetchTodos
function twice 😡.
React Router is not a cache
But when navigating between pages (back and forth), the mayor downside is not able to render stale data, then re-fetch and fianlly re-render if any updates exits.
Although, this is possible with React Query due to its cache capabilities. In other words, when we visit a route that is using React Router Loaders, that data is being re-fetch in every visit.
Is it not possible to have the best of both worlds (fetching early and having a cache)?
React Router meets React Query
And inside the component:
Many approaches use the hook
from the React Query library but I prefer this one since it did not cause any additional re-render for the first load. It will render the component the first time with no data and then re-render with the data available.
The problem with useQuery
from the React Query library
Maybe some configuration in my implementation using the useQuery
hook was wrong (please 🙏 shed some light in the comments). But the first time the component renders the data came undefined
.
Data invalidation
One interesting challenge still remained, how to invalidate queries? since they are being cached by ensureQueryData
🤔 query invalidation using invalidateQueries
API would not work, so I was in panic 😱.
Thankfully, React Query comes with pretty handy APIs for clean out the cache.
Conclusion
The real value from integrating data libraries (React Query and React Router) is that we can still use data cache skills from React Query and keep the fetching-sooner feature that React Router loaders is bringing to us.
Common issues
When approaching to this data libraries integration the common pattern is:
But I was getting undefined
from my query, in the first render. I could use isPending
return value from useQuery API
and then come back to a fallback UI (but that was out of question).
That will blurry away one of the benefits from using data loaders from React Router.
Resources
Stackademic
Thank you for reading until the end. Before you go:
- Please consider clapping and following the writer! 👏
- Follow us on Twitter(X), LinkedIn, and YouTube.
- Visit Stackademic.com to find out more about how we are democratizing free programming education around the world.