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:

initial folder structure

The setup

Install some core dependencies:

We added some polyfills and some Redux related dependencies, let’s identify what are they used for:

Setup the Redux store instance in state.js file:

state.js setup

And wrap our App component with Redux Provider:

index.js setup

That’s it, we’re ready to start caching 🚀

Let’s call an API

We’ll be using News API to fetch top headlines from Hacker News. 10 minutes is probably a reasonable cache time, so we will use a caching strategy to define the logic in the App.js file.

App.js setup

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).

User welcome title in Header component
Different call-to-action button based on user type

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:

Updated state.js

Notice the apiNormalizer middleware — it is used to recover from broken state (when user closes the tab, but the request was in progress).

And wrap our App with PersistGate component:

Updated index.js

Refresh the page and notice the state getting restored:

Recovering state from storage

Check the full source code.

Conclusion

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:

Happy caching!

On reaching me out — karolis.sh

Engineering Manager at Nord Security