UNPKG

redux-tiles

Version:

Library to create and easily compose redux pieces together in less verbose manner

76 lines (67 loc) 2.56 kB
import { forEachRight, get, isFunction, mapValues } from 'lodash'; import { Action, Reducer } from 'redux'; import { ReducerObject } from './types'; /** * @overview create reducer function from the object * @param {Any} initialState – initial state of this part of the store * @param {Object} handlers – object with keys as action types, and * reduce functions to change store as values * @return {Function} – function to act as a reducer */ export function createReducerFromObject(initialState: any, handlers: ReducerObject): Reducer<any> { return function reducer(state: {} = initialState, action: Action): {} { const handler: Function|{} = handlers[action.type]; return typeof handler === 'function' ? handler(state, action) : state; }; } /** * @overview create reducer from the object, with creating reducing functions * @param {Any} initialState – initial state of this part of the store * @param {Object} handlers – object with keys as action types, and * newValues to set at store as values * @return {Function} – function to act as a reducer */ export function createReducer(initialState: any, handlers: ReducerObject): Reducer<any> { return createReducerFromObject( initialState, mapValues(handlers, (value: any) => (state: any, action: Action): any => reducerCreator({ state, action, newValue: isFunction(value) ? value(state, action) : value })) ); } /** * @overview reducer function, which changes the state with new values * @param {Object} action – reducer action object, with type and payload * @param {Object} state – previous redux state in this branch * @param {Any} newValue – new value to set up in state in corresponding path * @return {Object} – changed reducer */ export function reducerCreator({ action, state, newValue }: any): any { const { path } = action.payload; const hasNoNestInStore: boolean = !path; if (hasNoNestInStore) { return newValue; } let result: any = {}; let lookupPath: string[]; // index stays as it was in original array, so the first // element in the iteration has `i` of the last element! forEachRight(path, (el: string, i: number) => { const isLastItem: boolean = i === path.length - 1; const newNestedResult: any = { [el]: isLastItem ? newValue : result }; lookupPath = path.slice(0, i); const oldState: any = get(state, lookupPath) || {}; result = { ...oldState, ...newNestedResult }; }); return { ...state, ...result }; }