UNPKG

@zedux/core

Version:

A high-level, declarative, composable form of Redux

65 lines (52 loc) 1.75 kB
import { Action, Reactable, ReducerBuilder, SubReducer } from '../types' import { extractActionType, extractActionTypes } from '../utils/actions' interface ReducersMap<State> { [key: string]: SubReducer<State>[] } /** Creates a new ReducerBuilder. A ReducerBuilder is just a reducer with a special `.reducer()` method for easily mapping action types to sub-reducers that handle them. */ export const createReducer = <State = any>(initialState?: State) => { const actionToReducersMap: ReducersMap<State> = {} const reducer = ((state: State = initialState as State, action: Action) => { const reducers = actionToReducersMap[action.type] || [] return runReducers(reducers, state, action) }) as ReducerBuilder<State> reducer.reduce = <Payload = any, Type extends string = any, Meta = any>( reactable: Reactable<Payload, Type> | Reactable<Payload, Type>[], subReducer: SubReducer<State, Payload, Type, Meta> ) => { const method = 'ReducerBuilder.reduce()' const actionTypes = Array.isArray(reactable) ? extractActionTypes(reactable, method) : [extractActionType(reactable, method)] mapActionTypesToReducer(actionToReducersMap, actionTypes, subReducer) return reducer } return reducer } const mapActionTypesToReducer = <State>( map: ReducersMap<State>, actionTypes: string[], consumer: SubReducer ) => { actionTypes.forEach(actionType => { if (!map[actionType]) { map[actionType] = [] } map[actionType].push(consumer) }) } const runReducers = <State>( reducers: SubReducer[], state: State, action: Action ) => { return reducers.reduce( (accumulatedState, reducer) => reducer(accumulatedState, action.payload, action), state ) }