use-async.ts 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import * as React from 'react'
  2. import useSafeDispatch from './use-safe-dispatch'
  3. import { Nullable } from '../../../../types/utils'
  4. type State<T> = {
  5. status: 'idle' | 'pending' | 'resolved' | 'rejected'
  6. data: Nullable<T>
  7. error: Nullable<Error>
  8. }
  9. type Action<T> = Partial<State<T>>
  10. const defaultInitialState: State<null> = {
  11. status: 'idle',
  12. data: null,
  13. error: null,
  14. }
  15. function useAsync<T = any>(initialState?: Partial<State<T>>) {
  16. const initialStateRef = React.useRef({
  17. ...defaultInitialState,
  18. ...initialState,
  19. })
  20. const [{ status, data, error }, setState] = React.useReducer(
  21. (state: State<T>, action: Action<T>) => ({ ...state, ...action }),
  22. initialStateRef.current
  23. )
  24. const safeSetState = useSafeDispatch(setState)
  25. const setData = React.useCallback(
  26. (data: Nullable<T>) => safeSetState({ data, status: 'resolved' }),
  27. [safeSetState]
  28. )
  29. const setError = React.useCallback(
  30. (error: Nullable<Error>) => safeSetState({ error, status: 'rejected' }),
  31. [safeSetState]
  32. )
  33. const reset = React.useCallback(
  34. () => safeSetState(initialStateRef.current),
  35. [safeSetState]
  36. )
  37. const runAsync = React.useCallback(
  38. (promise: Promise<T>) => {
  39. safeSetState({ status: 'pending' })
  40. return promise.then(
  41. data => {
  42. setData(data)
  43. return data
  44. },
  45. error => {
  46. setError(error)
  47. return Promise.reject(error)
  48. }
  49. )
  50. },
  51. [safeSetState, setData, setError]
  52. )
  53. return {
  54. isIdle: status === 'idle',
  55. isLoading: status === 'pending',
  56. isError: status === 'rejected',
  57. isSuccess: status === 'resolved',
  58. setData,
  59. setError,
  60. error,
  61. status,
  62. data,
  63. runAsync,
  64. reset,
  65. }
  66. }
  67. export default useAsync
  68. export type UseAsyncReturnType = ReturnType<typeof useAsync>