yet another state management Angular library
Michał Michalczuk
Ciklum / Stibo Systems
infoShare Academy
yet another state management Angular library
Michał Michalczuk
NGXS is a state management pattern + library for Angular.
...
NGXS is modeled after the CQRS pattern popularly implemented in libraries like Redux and NGRX but reduces boilerplate by using modern TypeScript features such as classes and decorators.
// dependencies
"@ngxs/store": "^3.4.3",
// devDependencies
"@ngxs/devtools-plugin": "^3.4.3",
// dependencies
"@ngrx/effects": "^7.4.0",
"@ngrx/store": "^7.4.0",
// devDependencies
"@ngrx/store-devtools": "^7.4.0",
@NgModule({
imports: [
...
NgxsModule.forRoot([CartState]),
NgxsReduxDevtoolsPluginModule.forRoot({
disabled: environment.production,
maxAge: 25
})
],
})
export class AppModule {}
@NgModule({
imports: [
...
StoreModule.forRoot(reducers),
EffectsModule.forRoot([]),
AppRoutingModule,
StoreDevtoolsModule.instrument({
maxAge: 25,
logOnly: environment.production
})
],
})
export class AppModule {}
// store/index.ts
export interface RootStore {
cart: CartStore;
}
export const reducers: ActionReducerMap<RootStore> = {
cart,
};
export * from './cart.reducer';
// cart.reducer.ts
const initialState = {
stickers: [] as Sticker[],
tshirts: [] as Tshirt[]
} as CartStore;
export interface CartStore {
stickers: Sticker[];
tshirts: Tshirt[];
}
export class StickerAddAction implements Action {
type = 'STICKER_ADD';
constructor(public payload: Sticker) {}
}
export const cart = (state = initialState, action: CartActions):
CartStore =>
{
switch (action.type as string) {
case 'STICKER_ADD':
return {
...state,
stickers: [
...state.stickers,
{...action.payload}
]
};
default:
return state;
}
};
// cart.state.ts
export interface CartStateModel {
stickers: Sticker[];
tshirts: Tshirt[];
}
export class AddSticker {
static readonly type = '[cart] add sticker';
constructor(public payload: Sticker) {}
}
@State<CartStateModel>({
name: 'cart',
defaults: {
stickers: [] as Sticker[],
tshirts: [] as Tshirt[]
}
})
export class CartState {
@Action(AddSticker)
addSticker({ patchState, getState }: StateContext<CartStateModel>,
{ payload }: AddSticker): void
{
const state = getState();
patchState({
stickers: [
...state.stickers,
payload
]
});
}
}
const currentStickers: Sticker[] =
this.store.selectSnapshot(state => state.stickers.stickers);
Anywhere in your app
import { ..., NgxsOnInit } from '@ngxs/store';
@State<StickersStateModel>({ ... }})
export class StickersState implements NgxsOnInit {
ngxsOnInit(context?: StateContext<StickersState>) {
if (context) {
ctx.dispatch(new FetchStickers());
}
}
...
}
import { Store, Actions, ofActionSuccessful } from '@ngxs/store';
export class AppComponent implements OnInit, OnDestroy {
constructor(private store: Store,
private actions: Actions) {
}
ngOnInit(): void {
this.actions
.pipe(
ofActionSuccessful(AddSticker)
)
.subscribe(
(action: AddSticker) => console.log(
`${action.payload.name} sticker bought!`
)
);
}
...
}
Yes please