2022-04-08 07:00:46 -04:00
|
|
|
import * as React from 'react'
|
|
|
|
import useSafeDispatch from './use-safe-dispatch'
|
|
|
|
import { Nullable } from '../../../../types/utils'
|
|
|
|
|
|
|
|
type State = {
|
|
|
|
status: 'idle' | 'pending' | 'resolved' | 'rejected'
|
|
|
|
data: Nullable<unknown>
|
|
|
|
error: Nullable<Record<string, unknown>>
|
|
|
|
}
|
|
|
|
type Action = Partial<State>
|
|
|
|
|
|
|
|
const defaultInitialState: State = { status: 'idle', data: null, error: null }
|
|
|
|
|
|
|
|
function useAsync(initialState?: Partial<State>) {
|
2022-04-22 09:49:26 -04:00
|
|
|
const initialStateRef = React.useRef({
|
|
|
|
...defaultInitialState,
|
|
|
|
...initialState,
|
|
|
|
})
|
2022-04-08 07:00:46 -04:00
|
|
|
const [{ status, data, error }, setState] = React.useReducer(
|
|
|
|
(state: State, action: Action) => ({ ...state, ...action }),
|
2022-04-22 09:49:26 -04:00
|
|
|
initialStateRef.current
|
2022-04-08 07:00:46 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
const safeSetState = useSafeDispatch(setState)
|
|
|
|
|
|
|
|
const setData = React.useCallback(
|
|
|
|
data => safeSetState({ data, status: 'resolved' }),
|
|
|
|
[safeSetState]
|
|
|
|
)
|
|
|
|
|
|
|
|
const setError = React.useCallback(
|
|
|
|
error => safeSetState({ error, status: 'rejected' }),
|
|
|
|
[safeSetState]
|
|
|
|
)
|
|
|
|
|
2022-04-22 09:49:26 -04:00
|
|
|
const reset = React.useCallback(
|
|
|
|
() => safeSetState(initialStateRef.current),
|
|
|
|
[safeSetState]
|
|
|
|
)
|
|
|
|
|
2022-04-08 07:00:46 -04:00
|
|
|
const runAsync = React.useCallback(
|
2022-04-22 09:49:26 -04:00
|
|
|
<T>(promise: Promise<T>) => {
|
2022-04-08 07:00:46 -04:00
|
|
|
safeSetState({ status: 'pending' })
|
|
|
|
|
2022-04-22 09:49:26 -04:00
|
|
|
return promise.then(
|
|
|
|
data => {
|
|
|
|
setData(data)
|
|
|
|
return data
|
|
|
|
},
|
|
|
|
error => {
|
|
|
|
setError(error)
|
|
|
|
return Promise.reject(error)
|
|
|
|
}
|
|
|
|
)
|
2022-04-08 07:00:46 -04:00
|
|
|
},
|
|
|
|
[safeSetState, setData, setError]
|
|
|
|
)
|
|
|
|
|
|
|
|
return {
|
|
|
|
isIdle: status === 'idle',
|
|
|
|
isLoading: status === 'pending',
|
|
|
|
isError: status === 'rejected',
|
|
|
|
isSuccess: status === 'resolved',
|
|
|
|
setData,
|
|
|
|
setError,
|
|
|
|
error,
|
|
|
|
status,
|
|
|
|
data,
|
|
|
|
runAsync,
|
2022-04-22 09:49:26 -04:00
|
|
|
reset,
|
2022-04-08 07:00:46 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default useAsync
|
|
|
|
export type UseAsyncReturnType = ReturnType<typeof useAsync>
|