Skip to content

Instantly share code, notes, and snippets.

@justinobney
Created January 24, 2020 07:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinobney/9e8f411a1e7a6f0fcc95b89978230142 to your computer and use it in GitHub Desktop.
Save justinobney/9e8f411a1e7a6f0fcc95b89978230142 to your computer and use it in GitHub Desktop.
import produce, {Draft} from 'immer';
import {useReducer, useMemo} from 'react';
type ActionCreator<State, Payload> = (
payload: Payload
) => {type: string; payload: Payload};
type CreatedAction<State, Payload> = ActionCreator<State, Payload> & AnyAction;
type Handler<State, Payload> = (state: Draft<State>, payload: Payload) => void;
type Handlers<State> = {
[actionType: string]: Handler<State, any>;
};
interface AnyAction {
type: any;
}
interface Reducer<State> {
initialState: State;
when: <Payload>(
action: CreatedAction<State, Payload>,
handler: Handler<State, Payload>
) => Reducer<State>;
build: () => Handlers<State>;
}
export const actionCreatorFactory = <State>() => <Payload>(key: string) => {
const cb = (payload: Payload) => ({type: key, payload});
((cb as unknown) as AnyAction).type = key;
return (cb as unknown) as CreatedAction<State, Payload>;
};
export const createReducer = <State>(initialState?: State) => {
const reducer: Reducer<State> = {
initialState,
} as Reducer<State>;
const handlers: Handlers<State> = {};
reducer.when = <Payload>(
action: CreatedAction<State, Payload>,
handler: Handler<State, Payload>
) => {
handlers[action.type] = handler;
return reducer;
};
reducer.build = () => {
const buildReducer = Object.keys(handlers).reduce((acc, key) => {
acc[key] = (state, payload) =>
produce(state, draft => {
handlers[key](draft, payload);
});
return acc;
}, {});
return buildReducer;
};
return reducer;
};
export const useImmerReducer = <State>(
reducer: Reducer<State>,
initialState?: State
) => {
const handlers = useMemo(() => reducer.build(), [reducer]);
return useReducer((state, action) => {
if (handlers[action.type]) {
return handlers[action.type](state, action.payload);
}
return state;
}, initialState ?? reducer.initialState);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment