Last active
July 22, 2021 15:23
-
-
Save Munawwar/4fd9502f14c60828a99de6500fd8b3e5 to your computer and use it in GitHub Desktop.
Async state fetching hook (for react)
This file contains hidden or 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
import { useEffect, useState } from 'react'; | |
/** | |
* @template T | |
* @param {(previousState: T) => Promise<T>} getAsyncState async function to fetch state | |
* @param {T} initialState | |
* @param {any[]} [dependencies=[]] similar to useEffect dependencies. change in dependencies will | |
* automatically call getAsyncState again | |
* @returns {[T, (newState: T) => void, () => Promise<void>]} [state, setState, refetch] | |
*/ | |
function useAsyncState( | |
getAsyncState, | |
initialState, | |
dependencies = [], | |
) { | |
const [state, setState] = useState(initialState); | |
let ignoreFetch = false; | |
const refetch = async () => { | |
const newState = await getAsyncState(state); | |
if (!ignoreFetch) { | |
setState(newState); | |
} | |
}; | |
useEffect(() => { | |
refetch(); | |
return () => { | |
// ignore fetch because either a new request has begun, making the in-flight request | |
// potentially stale or component got destroyed, meaning you shouldn't update anything now. | |
ignoreFetch = true; | |
}; | |
}, dependencies); | |
return [state, setState, refetch]; | |
} | |
export default useAsyncState; |
Example 3:
const [settings, setSettings] = getAsyncState(async () => axios.get('/settings'));
// form fields can use setSettings() now, like regular setState
setSettings({ name: event.target.value });
Example 4, fetch a list based on search text:
// outside component, debounced search function
const search = debounce((text) => axios.get('/search', { params: { q: text } }), 200);
// inside component
const [searchText, setSearchText] = useState('');
const [{ loading, results }, setList] = getAsyncState(
async (currentState) => {
setList({ loading: true, results: currentState.results });
const results = await search(searchText);
return { loading: false, results };
},
{ loading: true, results: [] },
[searchText],
);
// inside search onChange handler all you go to do is setSearchText(newText);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example 1
Example 2 (builds on example 1):