How do I implement caching in Redux?

react-redux cache api response
redux store size
redux garbage collection
redux-batch
redux-batched-subscribe
redux-thunk
react-cache
redux store api response

I would like to avoid calling an API twice if I already have the data in my store.

How do I do this with Redux?

I'm assuming you are using async actions to handle your API calls.

This is the place where I would put the caching logic, which results in a nice encapsulation:

export function fetchData(url) {   
    return function (dispatch) {
        dispatch(requestData(url))

        if (isCached(url)) {
            const cachedData = getCached(url)
            dispatch(receiveData(url, cachedData))
        } else {
            return fetch(url)
              .then(response => response.json())
              .then(json => {
                  dispatch(receiveData(url, json))
                  setCached(url, json)
              })
        }
    }
}

Implementing isCached, getCached and setCached for your local storage should be rather straightforward.

Caching, With that said, bindings for view libraries, such as React, are the perfect place for caching to be implemented. Official React bindings for Redux Resource are in  we've implemented api cache using memory-cache and writing simple cachedRequest function that we used in api/actions (see below). It is very simple one, it is set to 60 seconds as you can see, in other part of app we have also webhook to invalidate this cache so we could probably switch it to more than 60 sec.

The ideal solution to this in my opinion is to use Reselect selectors (https://github.com/reactjs/reselect). Here is a contrived example:

import { createSelector } from 'reselect';

const getObjs = state => state.objs;
const currentObjId = state => state.currentObjId;

export const getObj = createSelector(
  [ currentObjId, getObjs ],
  (id, objs) => objs.get(href)
);

Used like this:

import { getObj } from './selectors';

const ExampleComponent = ({obj}) => <div>{ obj.name }</div>;

const mapStateToProps = state => ({
  obj: getObj(state)
});

export default connect(mapStateToProps)(ExampleComponent);

The first time you run this, one obj based on some id (also in the state) will be "selected" from the list of all objs. The next time, if the inputs have not changed (look at reselect documentation for the definition of equivalence) it will simply return the computed value from last time.

You also have the option to plug-in a different type of cache, e.g. LRU. That's a bit more advanced, but very doable.

The major advantage of Reselect is that it allows you to cleanly optimise without manually maintaining extra state in redux that you would then have to remember to update if a change to the original data was made. Timo's answer is good, but I would argue that the weakness is that it doesn't cache expensive client side computation (I know this wasn't the exact question, but this answer is about best practice redux caching in general, applied to your problem), only fetching. You can do something very similar to what Timo suggests, but incorporate reselect for a very tidy solution. In an action creator you could have something like this:

export const fetchObj = (dispatch, getState) => {
  if (hasObj(getState())) {
    return Promise.resolve();
  }

  return fetchSomething()
    .then(data => {
      dispatch(receiveObj(data));
      return data;
    });
};

You would have a selector specifically for hasObj potentially based on the above selector (I do so here specifically to show how you can compose selectors easily), like:

export const hasObj = createSelector(
  [ getObj ],
  obj => !!obj
);

Once you start using this to interface with redux, it starts to make sense to use it exclusively in mapStateToProps even for simple selects so that at a future time, if the way that state is computed changes, you do not need to modify all of the components which use that state. An example of this might be something like having an array of TODOs when is used to render a list in several different components. Later in your application development process you realise you want to filter that list of TODOs by default to only ones that are incomplete. You change the selector in one place and you are done.

Performance, Will caching remote data cause memory problems? complex situations, there's nothing inherently slow or inefficient about how Redux is implemented. In fact  #Redux FAQ #Table of Contents. General. When should I learn Redux? When should I use Redux? Can Redux only be used with React? Do I need to have a particular build tool to use Redux? Reducers. How do I share state between two reducers? Do I have to use combineReducers? Do I have to use the switch statement to handle actions? Organizing State

I came up with the same problem, where I wanted to add a cache layer between my action and reducer. My solution was to create a middleware, to cache the Request action before it goes to the actual thunk, which request data from the API.

Doing this has a pros that you don't need to modify your existing action and reducer. You just add a middleware. Here is how the middleware look like:

const cache = store => next => action => {
  // handle FETCH action only
  if (action.type !== 'FETCH') {
    return next(action);
  }

  // check if cache is available
  const data = window['__data'];
  if (!data) {
    // forward the call to live middleware
    return next(action);
  }
  return store.dispatch({ type: 'RECEIVE', payload: { data: `${data} (from cache)` } });
}

export default cache;

Try out the live demo at https://stackblitz.com/edit/redux-cache-middleware or check out my blog post for more info http://www.tonnguyen.com/2018/02/13/web-programming/implement-a-cache-middleware-for-redux/

JumboInteractiveLimited/redux-cache: Client side TTL , redux-cache. This library provides an easy to use client side TTL caching strategy for redux applications. Often, it is unnecessary to refetch data from an API if we  In an actual Redux example, the state object could be built by combining two separate reducers to act independently on the byHash and byId properties of the state object to simply the logic.

Don't reinvent caching, just leverage the HTTP cache. Your code should be practically unaware of the caching mechanism. Simply make the http request when you need the data, it doesn't matter if it is through redux thunks, promises, etc or directly without redux. The HTTP cache will do the caching for you. Of course for this to work you need to properly configure your server to set the appropriate caching parameters and validity.

Caching a filtered list of results w/ Redux, React Router, and redux , changeQuery - a function used to update the query string. See the implementation here. the route is the single source of truth for the make and  Caching data will cause performance problems when the size of the cache approaches the amount of available memory. This tends to be a problem when the cached data is exceptionally large or the session is exceptionally long-running. And while it is good to be aware of the potential for these problems,

A simple and fast way to do it (although not recommended for anything scalable):

Use redux-persist to persist (cache) the store. Whenever it rehydrates, you know the data you had previously is present - read the docs in the link for how it works and how to setup.

To avoid unnessecary data-fetches on the remote server, you can cache the URLs (as Timos answer) to the localStorage or such, and simply check for its existence before doing the actual fetch.

Action:

    function fetchUsers(url){
        if(isCached(url)) {
            // The data is already in the store, thanks to redux-persist.
            // You can select it in the state as usual.
            dispatch({ type: 'IS_CACHED', payload: url })
        } else {
            return fetch(url)
                   .json()
                   .then((response) => {
                       dispatch({ type: 'USERS_FETCH_SUCCESS', payload: response.data })
                       setCached(url)
                   })
                   .catch((error) => {
                       dispatch({ type: 'USERS_FETCH_FAILED', payload: error })
                   })
        }
    }

Simple custom-cache for urls:

const CACHE_NAME = 'MY_URL_CACHE'

export function getUrlCache() {

    var localStorage
    try {
        localStorage = window.localStorage
        // Get the url cache from the localstorage, which is an array
        return ( localStorage.getItem(CACHE_NAME) ? JSON.parse(localStorage.getItem(CACHE_NAME)) : [] )
    } catch(e){
        // Make your own then...
        throw "localStorage does not exist yo"
    }
}

export function isCached(url) {
    var urlCache = getUrlCache()
    return urlCache.indexOf(url) !== -1
}

export function setCached(url){ 
    if( isCached(url) )
        return false

    var urlCache = getUrlCache()
    urlCache.push(url)

    localStorage.setItem(CACHE_NAME, urlCache)

    return true
}

export function removeCached(url){
    var myCache = getUrlCache()
    var index = myCache.indexOf(url)
    if(index !== -1){
        myCache = myCache.splice(index, 1)
        localStorage.setItem(CACHE_NAME, urlCache)
        return true
    } else {
        return false
    }
}

You would also need to remove the cached url when/if the redux-persist data is flushed or some other thing that makes the data "old".

I recommend doing the whole thing using the redux store with persisting, and rather model the reducer/action logic on it. There are many ways to do it, and I highly recommend exploring redux, redux-saga and redux-persist and common concepts/design patterns.

Sidenote on basic example: You can also use redux-persist-transform-expire transformer for redux-persist to let cached data expire at some point in time, and modify it to remove the relevant cached url while doing so.

Caching API resources with Redux - Karolis Šarapnickis, 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  This makes the state difficult to maintain and less predictable. It also means passing data to components that do not need such data. It’s clear that state management gets messy as the app gets complex. This is why you need a state management tool like Redux that makes it easier to maintain these states.

Redux Patterns: Caching an API Response, Redux Patterns: Caching an API Response I wrote a post the other day about how to implement a Redux-flavored store and reducer in a  Simply make the http request when you need the data, it doesn't matter if it is through redux thunks, promises, etc or directly without redux. The HTTP cache will do the caching for you. Of course for this to work you need to properly configure your server to set the appropriate caching parameters and validity.

Implement a cache middleware for Redux, One of the reason I love Redux so much, is the ability of providing alternative UIs while reusing most of the business logic. The thinner… To summarise, Install redux-persist in you project. Import persistStore and autoRehydrate form redux-persist. Add autoRehydrate to your store. Pass your store to persistStore. Listen to the persist/REHYDRATE action on your reducer and populate state accordingly.

Making Instagram.com faster: Part 3, We use Redux to manage state on instagram.com, so at a high level the way we implemented this was to store a subset of our Redux store on the client in an  The most straightforward usage of a cache is simply to cache a value, and if it has been previously cached, return it directly from the cache. Consider that you make an API call “getUsers”. The most straightforward solution for implementing caching would look something like:

Comments
  • The SO mods usually frown upon "what is the best way" questions. It is stupid I know, but if you change that to say, "How do I do this" it will be more likely to not get closed. Right now it's flagged as a candidate for being closed because it is "primarily opinion-based"
  • We have written a lib for just this! github.com/JumboInteractiveLimited/redux-cache you set a TTL for your cache time and then it will debounce actions that update the reducer
  • But if I don't want/need to save the data in local storage, I only need the data for the current session?
  • The "local storage" referred to here is redux, not some persistent browser store. I think that is what you were asking anyway.
  • But in this solution, I am duplicate the data in my store and in memory (if I don't use local storage)
  • This may work to cache urls, but it doesn't cache data. For instance, say I have had some other call at some point that retrieved a list of users (e.g. from URL /api/users?someQuery=foo. Now I need to get a user; that user may or may not be in the list, but knowing whether or not /api/users?someQuery=foo is cached doesn't tell me that. Only looking at the actual store will tell me that.
  • why do you say has a "cons" - did you mean "drawback aka con", and did you actually mean "benefit? I'd see it as a benefit that you can make application wide changes in one place in the middleware.
  • Really sorry, I meant pros. Edited the post.