ngrx-slice
is a plugin that intends to provide the same functionalities
that Redux Toolkit createSlice provides. It is meant to be
opinionated.
npm install ngrx-slice
yarn add ngrx-slice
ngrx-slice
has immer
as its peerDependencies
so go ahead and install it:
npm install immer
yarn add immer
Visit NgRX Slice Documentations
NgRX has always been coupled with boilerplate. Even with the new Creator APIs, the amount of boilerplate needed to set up a single feature state is still a lot (to remember). To fully utilize NgRX for a Feature State, you'd need:
- Actions (
createAction
) - Selectors (
createSelector
andcreateFeatureSelector
) - Reducer (
createReducer
)
Regardless of whether you separate these entities into different files, or keep them in the same file, the cognitive
overhead is still there. ngrx-slice
solves this issue for me.
Here's an example of a CounterState
using createAction
, createSelector
, createFeatureSelector
,
and createReducer
// Actions
const increment = createAction("[Counter] increment");
const decrement = createAction("[Counter] decrement");
const double = createAction("[Counter] double");
const multiplyBy = createAction(
"[Counter] multiplyBy",
props<{ multiplier: number }>()
);
const multiplyBySuccess = createAction(
"[Counter] multiplyBy success",
props<{ value: number }>()
);
// Reducer
interface CounterState {
value: number;
increment: number;
decrement: number;
}
const initialState: CounterState = {
value: 0,
increment: 0,
decrement: 0,
};
const counterReducer = createReducer(
initialState,
on(increment, (state) => ({
...state,
value: state.value + 1,
increment: state.increment + 1,
})),
on(decrement, (state) => ({
...state,
value: state.value - 1,
decrement: state.decrement + 1,
})),
on(multiplyBySuccess, (state, action) => ({ ...state, value: action.value })),
on(double, (state) => ({ ...state, value: state.value * 2 }))
);
// Selectors
const selectCounterState = createFeatureSelector("counter");
const selectValue = createSelector(selectCounterState, (state) => state.value);
const selectIncrement = createSelector(
selectCounterState,
(state) => state.increment
);
const selectDecrement = createSelector(
selectCounterState,
(state) => state.decrement
);
There is an
Effect
that will handlemultiplyBy
action but this will be the same forngrx-slice
as well.
Or you can have everything in a Slice
import { createSlice } from 'ngrx-slice';
export interface CounterState {
value: number;
incrementCount: number;
decrementCount: number;
}
export const initialState: CounterState = {
decrementCount: 0,
incrementCount: 0,
value: 0,
};
export const {
actions: CounterActions,
selectors: CounterSelectors,
...CounterFeature
} = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value++;
state.incrementCount++;
},
decrement: (state) => {
state.value--;
state.decrementCount++;
},
},
});
Contributions welcome