Caching API resources with Redux
After implementing API request caching couple of times in recent years, I decided to give back to open-source community. So I published a library called redux-cached-api-middleware and thought I’d share my thoughts on why you’d want to cache API requests and how you can do it in your apps with fairly low effort.
Why cache API requests
Well caching helps to re-load your apps faster and I believe we all hate those loading spinners 😡…
Faster re-load times lead to better UX, and higher conversion rates. So if you wan’t higher revenue, you probably should consider this technique.
You probably already cache you web app’s static assets via caching headers, but you can go further than this and preserve the whole application state. That’s where redux-cached-api-middleware in combination with other well know libraries can fast track your project 🏎!
How to start caching 🤔
For learning purposes let’s build a minimalistic Hacker News app that displays top articles. The example will be a React app, but core ideology applies to any Redux project.
The create-react-app is an easy way to start:
Which should create a project with a structure, similar to this:
Install some core dependencies:
We added some polyfills and some Redux related dependencies, let’s identify what are they used for:
- redux-thunk — async actions in redux
- redux-api-middleware — middleware for calling APIs
- redux-cached-api-middleware — a light-weight library (uses above libs as peer dependencies) that adds caching capabilities
- redux-devtools-extension — hook your redux state with browser dev tools
Setup the Redux
store instance in
And wrap our
App component with Redux
That’s it, we’re ready to start caching 🚀
Let’s call an API
This way if
App component would be re-mounted in the 10 minute interval, the API response would be returned from the cache and not requested again.
This may not look that useful for one component, but when you have multiple components that need the data from the same endpoint — it can get really handy. For example at my workplace we have a
WithUserInfo component that fetches some basic user data and passes to another component (see render prop). We have multiple
WithUserInfo elements in the React tree, but the API still gets called only once (even when the cache gets outdated).
I really like this approach, because then you don’t have to load all the data in some
AppWrapper component . Every component not only encapsulates the representation part but also the API data source logic. This way you can achieve a progressive loading effect — data is requested only when a component that needs it is added to the React tree.
Recovering after page refresh
Another cool trick you can do with caching is persist your redux state to offline storage (for e.g.
localStorage) via redux-persist.
Let’s update our setup, so that even when user re-opens the tab the previous state will be in place:
apiNormalizer middleware — it is used to recover from broken state (when user closes the tab, but the request was in progress).
And wrap our
Refresh the page and notice the state getting restored:
Check the full source code.
Caching is great UX overall and progressive loading perceives that the application is loading faster. Everyone uses APIs differently, so the API wrappers have to be flexible:
- redux-api-middleware let’s you pass your own fetch implementation
- with redux-cached-api-middleware you can either pass a predefined caching strategy or define you own
On reaching me out — karolis.sh