Skip to content

Instantly share code, notes, and snippets.

@pffigueiredo
Last active April 27, 2021 10:20
Show Gist options
  • Save pffigueiredo/d92091b444e92d828f3a30af58c211d0 to your computer and use it in GitHub Desktop.
Save pffigueiredo/d92091b444e92d828f3a30af58c211d0 to your computer and use it in GitHub Desktop.
Fetch reducer state machine with typescript support
import { Dispatch, Reducer, useReducer } from 'react';
type Nullable<T> = T | null | undefined;
type FetchMachineState<DataT, ErrorT> = {
status: 'idle' | 'loading' | 'success' | 'failure';
data: Nullable<DataT>;
error: Nullable<ErrorT>;
};
type Event<DataT, ErrorT> =
| { type: 'FETCH' }
| { type: 'RESOLVE'; data: DataT }
| { type: 'REJECT'; error: ErrorT };
function useFetchStateMachine<DataT, ErrorT = string>(
initialData: Nullable<DataT>
): [FetchMachineState<DataT, ErrorT>, Dispatch<Event<DataT, ErrorT>>] {
const initialState: FetchMachineState<DataT, ErrorT> = {
status: 'idle',
data: initialData,
error: null,
};
function fetchReducer(
state: FetchMachineState<DataT, ErrorT>,
event: Event<DataT, ErrorT>
): FetchMachineState<DataT, ErrorT> {
switch (event.type) {
case 'FETCH':
return {
...state,
status: 'loading',
};
case 'RESOLVE':
return {
...state,
status: 'success',
data: event.data,
};
case 'REJECT':
return {
...state,
status: 'failure',
error: event.error,
};
default:
return state;
}
}
return useReducer<
Reducer<FetchMachineState<DataT, ErrorT>, Event<DataT, ErrorT>>
>(fetchReducer, initialState);
}
// USAGE EXAMPLE
// interface Person {
// name: string;
// age: number;
// }
// interface Error {
// message: string;
// }
// const [state, dispatch] = useFetchStateMachine<Person, Error>(null);
// dispatch({ type: 'FETCH' });
// dispatch({
// type: 'RESOLVE',
// data: {
// name: 'Pedro',
// age: 2,
// },
// });
// dispatch({
// type: 'REJECT',
// error: {
// message: 'Server Error',
// },
// });
export default useFetchStateMachine;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment