Created
January 25, 2019 17:00
-
-
Save tannerlinsley/dcd6181c1d5c836e1b2c8dfe65cc9c8c to your computer and use it in GitHub Desktop.
useCancellable, useRefresh combo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const useCancellable = fn => { | |
const requestRef = useRef(0) | |
return async (...args) => { | |
// Keep track of latest promise ID | |
const id = Date.now() | |
requestRef.current = id | |
// Wait for resolution | |
const res = await fn(...args) | |
if (requestRef.current !== id) { | |
// If a new request has happened... | |
throw new Error(useCancellable) | |
} | |
// All is well | |
return res | |
} | |
} | |
const useRefresh = (fn, time) => { | |
if (!time) { | |
throw new Error('useRefresh requires a time') | |
} | |
// Keep track of the last time requested | |
const lastRequestedRef = useRef(Date.now()) | |
// Any time we refresh... | |
const refresh = () => { | |
// Update the last requested | |
lastRequestedRef.current = Date.now() | |
// return the func | |
return fn() | |
} | |
// If and when the lastRequested changes, set | |
// a timeout to refresh after the time | |
useEffect( | |
() => { | |
const timeoutID = setTimeout(refresh, time) | |
return () => { | |
// If the lastRequested changes before the | |
// timeout, clear it and start over | |
clearTimeout(timeoutID) | |
} | |
}, | |
[lastRequestedRef.current] | |
) | |
// Supply the refresher | |
return refresh | |
} | |
function useSearches(guards = []) { | |
// Some crud state | |
const [loading, setLoading] = useState(false) | |
const [error, setError] = useState(null) | |
const [searches, setSearches] = useState([]) | |
// A cancellable promise will throw `useCancellable` | |
const getSearches = useCancellable(() => axios.get(`${endpoint}/searches`)) | |
// Build the refresher | |
const refresh = useRefresh(async () => { | |
setError(null) | |
setLoading(true) | |
try { | |
const { data } = await getSearches() | |
setSearches(data) | |
} catch (err) { | |
if (err === useCancellable) { | |
// Was cancelled | |
} | |
setError(err) | |
} finally { | |
setLoading(false) | |
} | |
}, 1000 * 60) | |
// When the guards change, refresh | |
useEffect(() => { | |
refresh() | |
}, guards) | |
return { searches, loading, error, refresh } | |
} | |
// Photo by Maksym Zakharyak on Unsplash |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment