Last active
November 15, 2021 09:17
-
-
Save aadityataparia/2d663db0827d39164dcd748468968bdb to your computer and use it in GitHub Desktop.
Async callback and effect hooks for React in JS and TS
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 { useCallback, useState, useEffect } from 'react' | |
const defaultState = { error: null, isLoading: false, result: null } | |
export const useAsyncCallback = (callback, deps = []) => { | |
const [state, setState] = useState(defaultState) | |
const cb = useCallback( | |
(...args) => { | |
const req = callback(...args) | |
setState({ error: null, isLoading: true, result: null }) | |
req.then(result => { | |
setState({ error: null, isLoading: false, result }) | |
return result | |
}).catch(error => { | |
setState({ error, isLoading: false, result: null }) | |
throw error | |
}) | |
return req | |
}, | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
deps | |
) | |
return { | |
...state, | |
callback: cb, | |
} | |
} | |
export const useAsyncEffect = (callback, deps) => { | |
const returnValues = useAsyncCallback(callback, deps) | |
useEffect(() => { | |
returnValues.callback() | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, deps) | |
return returnValues | |
} | |
/* | |
Usage: | |
const { isLoading, callback, error, result } = useAsyncCallback( | |
() => | |
fetch(a, b), | |
[a, b] | |
); | |
*/ |
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 { useCallback, useState, useEffect } from 'react'; | |
export type AsyncHookCallback<T> = (...args: any[]) => Promise<T>; | |
export type AsyncHookResult<T> = { | |
error: Error | null; | |
result: T | null; | |
isLoading: boolean; | |
callback: AsyncHookCallback<T>; | |
}; | |
const defaultState = { error: null, isLoading: false, result: null }; | |
/* | |
useCallback hook for async functions. | |
Usage: | |
const { isLoading, callback, error, result } = useAsyncCallback( | |
() => | |
fetch(a, b), | |
[a, b] | |
); | |
*/ | |
export const useAsyncCallback = <T>(callback: AsyncHookCallback<T>, deps = []): AsyncHookResult<T> => { | |
const [state, setState] = useState(defaultState); | |
const cb = useCallback( | |
(...args) => { | |
const req = callback(...args); | |
setState({ error: null, isLoading: true, result: null }); | |
req.then(result => { | |
setState({ error: null, isLoading: false, result }); | |
return result; | |
}).catch(error => { | |
setState({ error, isLoading: false, result: null }); | |
throw error; | |
}); | |
return req; | |
}, | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
deps, | |
); | |
return { | |
...state, | |
callback: cb, | |
}; | |
}; | |
/* | |
useEffect hook for async functions. | |
Usage: | |
const { isLoading, callback, error, result } = useAsyncEffect( | |
() => | |
fetch(a, b), | |
[a, b] | |
); | |
*/ | |
export const useAsyncEffect = <T>(callback: AsyncHookCallback<T>, deps: any[]): AsyncHookResult<T> => { | |
const returnValues = useAsyncCallback(callback, deps); | |
useEffect(() => { | |
returnValues.callback(); | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, deps); | |
return returnValues; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment