import React, { useRef, useReducer } from 'react' import { fetchJson } from 'apis' export function useFetchWithCache({ url, options, }) { const cache = useRef({}) const initialState = { status: 'idle', error: null, data: [], } const [state, dispatch] = useReducer((state, action) => { switch (action.type) { case 'FETCHING': return { ...initialState, status: 'fetching' } case 'FETCHED': return { ...initialState, status: 'fetched', data: action.payload } case 'FETCH_ERROR': return { ...initialState, status: 'error', error: action.payload } default: return state } }, initialState) React.useEffect(() => { let cancelRequest = false if (!url) return dispatch({ type: 'FETCHING' }) if (cache.current[url]) { const data = cache.current[url] dispatch({ type: 'FETCHED', payload: data }) } else { fetchJson(url, options) .then(json => { if (!cancelRequest) { cache.current[url] = json dispatch({ type: 'FETCHED', payload: json }) } }) .catch(err => { if (!cancelRequest) { dispatch({ type: 'FETCH_ERROR', payload: err }) } }) } return function cleanup() { cancelRequest = true } }, [url]) return [ state.data, state.error, state.status] }