Skip to content

Instantly share code, notes, and snippets.

@jeferson-sb
Last active June 3, 2025 19:06
Show Gist options
  • Save jeferson-sb/561e4a510168ca9f616a2f62f9e334a8 to your computer and use it in GitHub Desktop.
Save jeferson-sb/561e4a510168ca9f616a2f62f9e334a8 to your computer and use it in GitHub Desktop.
A better useReducer hook ('cause we're in 2025 -- hello React team?)
import { useReducer } from 'react';
/**
* Usage:
*
* ```tsx
* const [state, actions] = useSmartReducer(
* { count: 0, isOn: false },
* {
* inc: (state) => ({ ...state, count: state.count + 1 }),
* toggleOn: (state) => ({ ...state, isOn: !state.isOn }),
* },
* );
* ```
*/
type ActionConfig<State, Actions> = {
[K in keyof Actions]: (state: State, payload: Actions[K]) => State;
};
type Action<K, P> = {
type: K;
payload: P;
};
const useSmartReducer = <State, Actions>(
initialState: State,
actionsConfig: ActionConfig<State, Actions>
) => {
type ActionType = keyof Actions;
type ReducerAction = Action<ActionType, any>;
const reducer = (state: State, action: ReducerAction): State => {
const actionFn = actionsConfig[action.type];
return actionFn ? actionFn(state, action.payload) : state;
};
const [state, dispatch] = useReducer(reducer, initialState);
const actions = (Object.keys(actionsConfig) as Array<ActionType>).reduce(
(acc, actionType) => {
acc[actionType] = (payload: Actions[ActionType]) =>
dispatch({ type: actionType, payload });
return acc;
},
{} as { [K in ActionType]: (payload: Actions[K]) => void }
);
return [state, actions] as const;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment