use-async.ts 1.7 KB

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