Skip to content

Instantly share code, notes, and snippets.

@arabold
Created November 2, 2019 16:51
Show Gist options
  • Save arabold/19d0b8310f30dfd82c79102d2464845f to your computer and use it in GitHub Desktop.
Save arabold/19d0b8310f30dfd82c79102d2464845f to your computer and use it in GitHub Desktop.
import { Dispatch, useState } from "react";
// Type definitions based on original React `Reducer<S, A>`
export type AsyncReducer<S, A> = (prevState: S, action: A) => Promise<S> | S;
export type AsyncReducerState<R extends AsyncReducer<any, any>> = R extends AsyncReducer<infer S, any> ? S : never;
export type AsyncReducerAction<R extends AsyncReducer<any, any>> = R extends AsyncReducer<any, infer A> ? A : never;
export const useAsyncReducer = <R extends AsyncReducer<any, any>>(
reducer: R,
initialState: AsyncReducerState<R>,
): [AsyncReducerState<R>, Dispatch<AsyncReducerAction<R>>] => {
const [state, setState] = useState(initialState);
const dispatch = async (action: AsyncReducerAction<R>) => {
const result = reducer(state, action);
if (result && typeof result.then === "function") {
// Result is a promise
try {
const newState = await result;
setState(newState);
} catch (err) {
setState({ ...state, error: err });
}
} else {
setState(result);
}
};
return [state, dispatch];
};
export default useAsyncReducer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment