Theo's Typesafe CultTTC
Theo's Typesafe Cult11mo ago
2 replies
Joppe

Feedback on Generated Redux hooks

Hey, I'm new to Redux/RTK and would like some feedback regarding two utility functions I wrote.
I'm a fan of custom hooks and saw that RTK can auto generate those. I'd like to emulate something similar but for a regular slice's selectors and actions.

I'd like to know:
- Is what I'm doing unconventional? If it is, is it bad practice (and why) or just not common but fine.
- Did I overlook some pitfalls? Like something that might cause unneeded/excessive re-renders?
- Just general thoughts on the overall approach or tips regarding the typings.

What I have right now can be used like this:
// todoSlice.ts
// ------------
const todoSlice = createSlice(/* stuff */)

// generated hooks match props in initialState but with the "use" prefix
export const { useTodos } = createSelectorHooks(todoSlice)
// hook that binds useDispatch to action creators when called in a component
export const useTodoActions = createActionHook(todoSlice)


// Component.tsx
// -------------
const Component = () => {
  const todos = useTodos()
  const { addTodo, toggleTodo } = useTodoActions()
}


The utility functions look like this:
function createActionHook<
  S extends Slice,
  A extends S["actions"],
  R extends {
    [K in keyof A]: (
      ...args: Parameters<A[K]>
    ) => ReturnType<Dispatch<ReturnType<A[K]>>>;
  }
>(slice: S) {
  return () => {
    const dispatch = useDispatch();
    return useMemo(
      () => bindActionCreators(slice.actions, dispatch),
      [dispatch]
    ) as unknown as R;
  };
}

function createSelectorHooks<
  S extends Slice,
  I extends ReturnType<S["getInitialState"]>,
  R extends { [key in Slice["reducerPath"]]: I },
  H extends { [K in keyof I as `use${Capitalize<string & K>}`]: () => I[K] }
>(slice: S) {
  return Object.fromEntries(
    Object.keys(slice.getInitialState()).map((key) => [
      `use${key[0].toUpperCase()}${key.slice(1)}`,
      () => useSelector((rootState: R) => rootState[slice.reducerPath][key]),
    ])
  ) as H;
}
Was this page helpful?