score:23

Accepted answer

you can cache in HDD or RAM.

  • HDD = e.g. localStorage
  • RAM = application state, e.g. redux store.

For localStorage you can use my little plugin for this: https://www.npmjs.com/package/localstorage-ttl

In app state (RAM) - fire action to fetch data, use redux-thunk, redux-saga or similar to make a call and with reducer save data in the store. Retrieve data from store.

https://github.com/gaearon/redux-thunk https://github.com/redux-saga/redux-saga

score:0

As I guessed you are using redux for state management. And You want to cache api calls for efficient controll state changes for avoiding rerendering Components, unnecessarry API calls and being friendly for Mobile Users (with avoiding fetchig same data(not changed) multiple time). If so -> then you can use ready solution for it.

redux-cache. please visit below link for additional information and investigate caching mechanizm briefly -> when you need cache data and when you need evict cache.

https://github.com/JumboInteractiveLimited/redux-cache

How do I implement caching in Redux?

score:0

If you have control over API you can tweak it so responses will be cached. https://web.dev/http-cache/

score:8

You could choose a redux-cached-api-middleware (disclaimer: I'm the author of this library), that's especially built for such cases.

Here's an example that might fit your case:

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import api from 'redux-cached-api-middleware';
import Dropdown from './Dropdown';
import Error from './Error';

class ExampleApp extends React.Component {
  componentDidMount() {
    this.props.fetchData();
  }

  render() {
    const { result } = this.props;
    if (!result) return null;
    if (result.fetching) return <div>Loading...</div>;
    if (result.error) return <Error data={result.errorPayload} />;
    if (result.successPayload) return <Dropdown items={result.successPayload} />;
    return <div>No items</div>;
  }
}

ExampleApp.propTypes = {
  fetchData: PropTypes.func.isRequired,
  result: PropTypes.shape({}),
};

const CACHE_KEY = 'GET/items';

const enhance = connect(
  state => ({
    result: api.selectors.getResult(state, CACHE_KEY),
  }),
  dispatch => ({
    fetchData() {
      return dispatch(
        api.actions.invoke({
          method: 'GET',
          headers: { Accept: 'application/json' },
          endpoint: 'https://my-api.com/items/',
          cache: {
            key: CACHE_KEY,
            strategy: api.cache
              .get(api.constants.SIMPLE_SUCCESS)
              .buildStrategy(),
          },
        })
      );
    },
  })
);

export default enhance(ExampleApp);

It will fetch from API only once, and whenever you call fetchData it will return data from the cache, even if the call is from another component.

The setup for this library is as follows:

import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { apiMiddleware } from 'redux-api-middleware';
import api from 'redux-cached-api-middleware';
import reducers from './reducers';

const store = createStore(
  combineReducers({
    ...reducers,
    [api.constants.NAME]: api.reducer,
  }),
  applyMiddleware(thunk, apiMiddleware)
);

With this approach after user re-loads the page all redux state will be lost, if you'd like to save that state you could choose a redux-persist library to sync the state to localStorage and use would probably use different caching strategy for redux-cached-api-middleware.


Related Query

More Query from same tag