Skip to content

Instantly share code, notes, and snippets.

@mamapi
Created March 9, 2021 12:30
Show Gist options
  • Select an option

  • Save mamapi/d4531e834a541af62c5dc1696afc4936 to your computer and use it in GitHub Desktop.

Select an option

Save mamapi/d4531e834a541af62c5dc1696afc4936 to your computer and use it in GitHub Desktop.

Revisions

  1. mamapi created this gist Mar 9, 2021.
    60 changes: 60 additions & 0 deletions useFetchWithCache.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    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]
    }