UNPKG

ngrx-handlers

Version:

NgRx Plugin for Generating Actions and Reducer Based on the Handler Map

141 lines (136 loc) 4.25 kB
import { __rest } from 'tslib'; import { createAction, props } from '@ngrx/store'; /** * Generates a map of action creators and reducer function based on the initial state, source and handler map. * * @param initialState An initial state of the reducer function. * @param source A source of the actions creators. * @param handlers A map where the keys are action events and the values are case reducers. * @returns A tuple of action creator map and the reducer function. * * @example * // movies.state.ts * interface MoviesState { * movies: Movie[]; * selectedMovieId: number | null; * searchTerm: string; * loading: boolean; * } * * const initMoviesState: MoviesState = { * movies: [], * selectedMovieId: null, * searchTerm: '', * loading: false, * }; * * // movies-page.handlers.ts * const [moviesPageActions, moviesPageReducer] = combineHandlers(initMoviesState, 'moviesPage', { * updateSelectedMovieId: (state, { selectedMovieId }: { selectedMovieId: number }) => ({ * ...state, * selectedMovieId, * }), * updateSearchTerm: (state, { searchTerm }: { searchTerm: string }) => ({ * ...state, * searchTerm, * }), * }); * * // movies-effects.handlers.ts * const [moviesEffectsActions, moviesEffectsReducer] = combineHandlers( * initMoviesState, * 'moviesEffects', * { * fetchMovies: state => ({ ...state, loading: true }), * fetchMoviesSuccess: (state, { movies }: { movies: Movie[] }) => ({ * ...state, * movies, * loading: false, * }), * fetchMoviesError: state => ({ ...state, movies: [], loading: false }), * }, * ); * * @see mergeReducers */ function combineHandlers(initialState, source, handlers) { return [createActions(source, handlers), createReducer(initialState, source, handlers)]; } /** * Creates a plain case reducer. * * @returns A plain case reducer. * * @example * const [moviesPageActions, moviesPageReducer] = combineHandlers(initMoviesState, 'moviesPage', { * showCreateMovieDialog: plain(), * }); * * @see combineHandlers */ function plain() { return state => state; } /** * Creates a plain case reducer with the payload. * * @returns A plain case reducer with the payload. * * @example * const [moviesPageActions, moviesPageReducer] = combineHandlers(initMoviesState, 'moviesPage', { * createMovie: withPayload<{ movie: Movie }>(), * }); * * @see combineHandlers */ function withPayload() { return plain(); } function createActions(source, handlers) { return Object.keys(handlers).reduce((actionMap, event) => (Object.assign(Object.assign({}, actionMap), { [event]: createAction(toActionType(source, event), props()) })), {}); } function createReducer(initialState, source, handlers) { return (state = initialState, action) => { const { type } = action, payload = __rest(action, ["type"]); const reducer = source === toSource(type) ? handlers[toEvent(type)] : null; return reducer ? reducer(state, payload) : state; }; } function toActionType(source, event) { return `[${source}] ${event}`; } function toSource(actionType) { return actionType.slice(1).split(']').shift(); } function toEvent(actionType) { return actionType.split('] ').pop(); } /** * Merges the array of reducers into one. * * @param reducers An array of reducers for the same state slice. * @returns A reducer merged from the provided reducers. * * @example * // movies.reducer.ts * const moviesReducer = mergeReducers(moviesPageReducer, moviesEffectsReducer); * * // movies.module.ts * \@NgModule({ * imports: [StoreModule.forFeature('movies', moviesReducer)], * }) * export class MoviesModule {} * * @see combineHandlers */ function mergeReducers(...reducers) { return (state, action) => { const reducer = reducers.find(r => r(state, action) !== state); return reducer ? reducer(state, action) : state; }; } /** * Generated bundle index. Do not edit. */ export { combineHandlers, mergeReducers, plain, withPayload }; //# sourceMappingURL=ngrx-handlers.js.map