Skip to content

like redux combineReducers but on hooks with typescript type inference

License

Notifications You must be signed in to change notification settings

alexpozdnyakof/use-combine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

useCombine hook for React

Pic by Craftwork Design

Zero-Dependency React hook to combine reducers to global complex state with single dispatch. It's like redux combineReducers with well typescript support. Use it with React Context.

Setup

with yarn

yarn add use-combine

with npm

npm install use-combine

Usage

import useCombine from 'use-combine';
import { useReducer } from 'react';


// User state slice
const userInitialState = { name: 'name' };
type UserAction = {type: 'login', payload: {name: string}} | {type: 'logout'}
const userReducer = (state, action: UserAction) => {
  switch(action.type) {
    case 'login': {
      state.name = action.payload.name
    }
    case 'logout': {
      state.name = null
    }
  }
}

// Todos state slice
const todosInitialState = { todos: [1, 2, 3] };
type TodosAction = {type: 'set', payload: Array<number>} | {type: 'reset'}
const todosReducer = (state, action: TodosAction) => {
  switch(action.type) {
    case 'set': {
      state.todos = action.payload
    }
    case 'logout': {
      state.todos = []
    }
  }
}


function App(){
  const [state, dispatch] = useCombine({
    user: useReducer(userReducer, userInitialState),
    todos: useReducer(todosReducer, todosInitialState),
  })

  const {user, todos} = state;

  return (
    <>
      <div>{user.name}</div>
      {todos.map(todo => <div key={todo}>{todo}</div>)}
    </>
  )
}

Usage with React Contenxt

//user-slice.ts
type UserState = {
  name: string | null
}

//todos-slice.tsx
type TodosState = {
  todos: Array<number>
}

//context.tsx
import useCombine from 'use-combine';
import { userReducer, userInitialState,  UserState, UserAction } from './slices/user-slice'
import { todosReducer, todosInitialState, TodosState, TodosAction } from './slices/todos-slice'

type AppState = {user: UserState, todos: TodosState};
type AppAction = UserAction & TodosAction;
type ContextProps = {
  state: AppState,
  dispatch: Dispatch<AppAction>
};
const AppStateContext = createContext<ContextProps>({} as ContextProps);

function AppStateProvider({children}: PropsWithChildren){
  const [state, dispatch] = useCombine<AppState, AppAction>({
    user: useReducer(userReducer, userInitialState),
    user: useReducer(todosReducer, todosInitialState),
  });

  const store = useMemo(() => ({ state, dispatch }), [state]);

  return (
    <AppStateContext.Provider value={store}>
      {children}
    </AppStateContext.Provider>
  )
}

export function useAppState() {
  return useContext(AppStateContext);
}

Tested With Vitests

About

like redux combineReducers but on hooks with typescript type inference

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published