Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save danielgek/c2bdc8fe7ce4cc075792d21c50febcb1 to your computer and use it in GitHub Desktop.
Save danielgek/c2bdc8fe7ce4cc075792d21c50febcb1 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 | None;
type FetchMachineState<DataT, ErrorT> = {
status: 'idle' | 'loading' | 'success' | 'failure';
data: Nullable<DataT>;
error: Nullable<ErrorT>;
};
type Action<DataT, ErrorT> =
| { type: 'FETCH' }
| { type: 'RESOLVE'; data: DataT }
| { type: 'REJECT'; error: ErrorT };
function useFetchStateMachine<DataT, ErrorT = string>(
initialData: Nullable<DataT>
): [FetchMachineState<DataT, ErrorT>, Dispatch<Action<DataT, ErrorT>>] {
const initialState: FetchMachineState<DataT, ErrorT> = {
status: 'idle',
data: initialData,
error: null,
};
function fetchReducer(
state: FetchMachineState<DataT, ErrorT>,
action: Action<DataT, ErrorT>
): FetchMachineState<DataT, ErrorT> {
switch (action.type) {
case 'FETCH':
return {
...state,
status: 'loading',
};
case 'RESOLVE':
return {
...state,
status: 'success',
data: action.data,
};
case 'REJECT':
return {
...state,
status: 'failure',
error: action.error,
};
default:
return state;
}
}
return useReducer<
Reducer<FetchMachineState<DataT, ErrorT>, Action<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