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