useStatelessReducer.ts 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. import { Action } from '@reduxjs/toolkit';
  2. import { createContext, useCallback, useContext } from 'react';
  3. export type Reducer<S, A extends Action> = (state: S, action: A) => S;
  4. export const combineReducers =
  5. <S, A extends Action = Action>(reducers: { [P in keyof S]: Reducer<S[P], A> }) =>
  6. (state: S, action: A): Partial<S> => {
  7. const newState = {} as S;
  8. for (const key in reducers) {
  9. newState[key] = reducers[key](state[key], action);
  10. }
  11. return newState;
  12. };
  13. export const useStatelessReducer = <State, A = Action>(
  14. onChange: (value: State) => void,
  15. state: State,
  16. reducer: (state: State, action: A) => State
  17. ) => {
  18. const dispatch = useCallback(
  19. (action: A) => {
  20. onChange(reducer(state, action));
  21. },
  22. [onChange, state, reducer]
  23. );
  24. return dispatch;
  25. };
  26. export const DispatchContext = createContext<((action: Action) => void) | undefined>(undefined);
  27. export const useDispatch = <T extends Action = Action>(): ((action: T) => void) => {
  28. const dispatch = useContext(DispatchContext);
  29. if (!dispatch) {
  30. throw new Error('Use DispatchContext first.');
  31. }
  32. return dispatch;
  33. };