Skip to content

Instantly share code, notes, and snippets.

@jtulk
Last active January 25, 2022 17:07
Show Gist options
  • Save jtulk/2b0d1082fdf331a52ec1e28556825406 to your computer and use it in GitHub Desktop.
Save jtulk/2b0d1082fdf331a52ec1e28556825406 to your computer and use it in GitHub Desktop.
Caching an API Response With Redux-Thunk
const numMinutesToStale = 60;
export const timeToStale = numMinutesToStale * 60 * 1000;
// Import the number of milliseconds before refetching
import { timeToStale } from './constants.js';
// First, define my allowed actions
const ACTIONS = {
abort: "abort",
error: "error",
start: "start",
update: "update"
}
// Log if a fetch is aborted by the async call running too aggressively.
export const abortFetch = () => ({
type: ACTIONS.abort
});
/**
* Log an error if the async call fails
* @param {object} error - the error thrown.
*/
export const errorFetch = error => ({
type: ACTIONS.error,
error
});
// Start the fetch, toggle is `isFetching` value
export const startFetch = () => ({
type: ACTIONS.start
});
/**
* Resolve the fetch with the returned data
* @param {object} payload - the data returned from the fetch
*/
export const updateFetch = payload => ({
type: ACTIONS.update,
payload
});
// Run the async fetch if the data is stale, otherwise abort the fetch and log it
export const updateDemoContentAsync = () => {
// Redux Thunk allows this, see its docs for more detail
return (dispatch, getState) => {
// Get the state of the store synchronously for the REDUCER IN QUESTION, e.g. myContent here
const timeSinceLastFetch = getState().myContent.lastFetched;
// perform the async call if the data is older than the allowed limit
const isDataStale = Date.now() - timeSinceLastFetch > timeToStale;
if (isDataStale) {
dispatch(startFetch());
// Run the async fetch
myApi.fetchData()
.then(content => {
dispatch(updateFetch(content));
})
.catch(err => {
dispatch(errorFetch(err));
});
} else {
dispatch(abortFetch());
}
};
};
const initialState = {
content: {},
error: null,
isFetching: false,
lastFetched: 0
}
const myContentReducer = (state = initialState, action = {}) => {
const { error, payload, type } = action;
switch (type) {
case ACTIONS.error: {
return {
...state,
error,
isFetching: false
};
}
case ACTIONS.startFetch: {
return {
...state,
isFetching: true
};
}
case ACTIONS.update: {
return {
...state,
content: payload,
error: null,
isFetching: false,
lastFetched: Date.now()
};
}
default: {
return state;
}
}
};
export default myContentReducer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment