Last active
July 14, 2022 14:50
-
-
Save danecando/b609aa27be51d8921c38804605e123a1 to your computer and use it in GitHub Desktop.
A utility hook for managing async effects in a component
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 * as React from 'react'; | |
enum Async { | |
START, | |
SUCCESS, | |
FAILURE, | |
} | |
interface AsyncState<T> { | |
isLoading: boolean; | |
error?: unknown; | |
isComplete: boolean; | |
value?: T; | |
} | |
type AsyncAction<T> = | |
| { | |
type: Async.START; | |
} | |
| { | |
type: Async.SUCCESS; | |
payload: { value?: T }; | |
} | |
| { | |
type: Async.FAILURE; | |
payload: { error: unknown }; | |
}; | |
interface ActionCreators<T> { | |
start: () => void; | |
success: (value?: T) => void; | |
failure: (error: unknown) => void; | |
} | |
function reducer<T>( | |
state: AsyncState<T>, | |
action: AsyncAction<T> | |
): AsyncState<T> { | |
switch (action.type) { | |
case Async.START: | |
return { | |
...state, | |
isLoading: true, | |
isComplete: false, | |
}; | |
case Async.SUCCESS: | |
return { | |
isLoading: false, | |
error: undefined, | |
isComplete: true, | |
value: action.payload.value, | |
}; | |
case Async.FAILURE: | |
return { | |
...state, | |
isLoading: false, | |
error: action.payload.error, | |
}; | |
} | |
} | |
export function useAsyncState<T>( | |
initialState?: Partial<AsyncState<T>> | |
): [AsyncState<T>, ActionCreators<T>] { | |
const [state, dispatch] = React.useReducer< | |
React.Reducer<AsyncState<T>, AsyncAction<T>> | |
>(reducer, { | |
isLoading: false, | |
error: undefined, | |
isComplete: false, | |
...initialState, | |
}); | |
const actionCreators = React.useMemo( | |
() => ({ | |
start: () => dispatch({ type: Async.START }), | |
success: (value?: T) => | |
dispatch({ type: Async.SUCCESS, payload: { value } }), | |
failure: (error: unknown) => | |
dispatch({ type: Async.FAILURE, payload: { error } }), | |
}), | |
[dispatch] | |
); | |
return [state, actionCreators]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment