ngrx-handlers
Version:
NgRx Plugin for Generating Actions and Reducer Based on the Handler Map
141 lines (136 loc) • 4.25 kB
JavaScript
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