Sinan Samet
Sinan Samet

Reputation: 6752

Is it possible to cache an api request with react native/redux?

I haven't been able to figure out if I can cache the api calls locally so that when I close the app and restart it it's still there.

On this page of Redux I saw that it is possible to cache with middleware like this:

  loadData(userId) {
    // Injected into props by React Redux `connect()` call:
    let { dispatch, posts } = this.props

    if (posts[userId]) {
      // There is cached data! Don't do anything.
      return
    }

    // Reducer can react to this action by setting
    // `isFetching` and thus letting us show a spinner.
    dispatch(loadPostsRequest(userId))

    // Reducer can react to these actions by filling the `users`.
    fetch(`http://myapi.com/users/${userId}/posts`).then(
      response => dispatch(loadPostsSuccess(userId, response)),
      error => dispatch(loadPostsFailure(userId, error))
    )
  }

Should I use that? And does the cache remain after closing the app?

Upvotes: 1

Views: 7457

Answers (2)

Karolis.sh
Karolis.sh

Reputation: 1738

As mentioned previously redux-persist will sync you redux state with offline storage. To save your API requests to the state you would need to implement that. Or you could use one of libraries created purely for that, eg. redux-cached-api-middleware (disclaimer I'm the author of this package).

Here's an example of fetching some data, and making the cache valid for 10 minutes:

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import api from 'redux-cached-api-middleware';
import Items from './Items';
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 <Items data={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.CACHE_TYPES.TTL_SUCCESS)
              .buildStrategy({ ttl: 10 * 60 * 1000 }), // 10 minutes
          },
        })
      );
    },
  })
);

export default enhance(ExampleApp);

* Note the API response will not be deleted after 10 minutes, but this.props.fetchData(); method when invoked will re-fetch from the endpoint, only if the cache is outdated.

Upvotes: 1

Jickson
Jickson

Reputation: 5193

We can use Redux Persist library to persist the redux store. By default this library will persist the entire redux store. But in your case you need to persist only some API calls. What you need to do is, add all the stores that has to be persisted to the whitelist like below.

 persistStore(
    store, {
        storage: AsyncStorage,
        whitelist: ['user','some_other_reducer'],
    }, onComplete);

You may refer f8App by facebook for the implementation details on how to set up redux persist.

Upvotes: 4

Related Questions