Skip to content

Instantly share code, notes, and snippets.

@hamzakaya
Created March 31, 2022 18:08
Show Gist options
  • Save hamzakaya/42e3295a48efc40de45c8a6c3c18f5b6 to your computer and use it in GitHub Desktop.
Save hamzakaya/42e3295a48efc40de45c8a6c3c18f5b6 to your computer and use it in GitHub Desktop.
import { useReducer, Reducer, Dispatch, useMemo } from "react";
type Action<T, P> = {
type: T;
payload: P;
};
type ActionMap<A> = {
[K in keyof A]: (payload?: A[K]) => void;
};
type ReducerMap<S, A> = {
[K in keyof A]: Reducer<S, Action<K, A[K]>>;
};
export default function useAppReducer<S, A>(
initialState: S,
reducerMap: ReducerMap<S, A>,
debug = false
): [S, ActionMap<A>] {
const [state, dispatch] = useReducer(makeReducer(reducerMap), initialState);
const actions = useMemo(
() => makeActions(reducerMap, dispatch, debug),
[reducerMap]
);
return [state, actions];
}
function makeReducer<S, A>(reducerMap: ReducerMap<S, A>) {
return (state: S, action: Action<keyof A, any>) => {
if (action && action.type && reducerMap[action.type]) return reducerMap[action.type](state, action);
return state;
};
}
function makeActions<S, A>(
reducerMap: ReducerMap<S, A>,
dispatch: Dispatch<Action<keyof A, any>>,
debug: boolean
): ActionMap<A> {
const types = Object.keys(reducerMap) as Array<keyof A>;
return types.reduce((actions: ActionMap<A>, type: keyof A) => {
if (!actions[type]) {
actions[type] = (payload: any) => {
const action = { type, payload };
dispatch(action);
// optionally log actions
if (debug) console.log(action);
};
}
return actions;
}, {} as ActionMap<A>);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment