ComponentStore
The Store is a wrapper around the NgRx Component Store. You have the exact same API plus the extras below.
state
state is a Signal<STATE>. Read it directly in your template.
import { Component, inject } from '@angular/core';
import { StoreFactory } from '@gernsdorfer/ngrx-lite';
interface MyState {
counter: number;
}
@Component({
template: `<h2>{{ counterState().counter }}</h2>`,
})
export class AppComponent {
private storeFactory = inject(StoreFactory);
private store = this.storeFactory.createComponentStore<MyState>({
storeName: 'BASIC_COUNTER',
defaultState: { counter: 0 },
});
public counterState = this.store.state;
}
state$
state$ is the Observable<STATE> from the NgRx Component Store.
Prefer state unless you need to compose the value with other streams.
import { Observable } from 'rxjs';
export class AppComponent {
private storeFactory = inject(StoreFactory);
private store = this.storeFactory.createComponentStore<MyState>({
storeName: 'BASIC_COUNTER',
defaultState: { counter: 0 },
});
public state$: Observable<MyState> = this.store.state$;
}
setState
Replace the complete state. Pass a custom action name as the second argument to find the change in the DevTools or to
share it with @ngrx/effects.
export class AppComponent {
private storeFactory = inject(StoreFactory);
private store = this.storeFactory.createComponentStore<MyState>({
storeName: 'BASIC_COUNTER',
defaultState: { counter: 0 },
});
change(counter: number) {
// logged with the default action name
this.store.setState({ counter });
}
changeWithCustomAction(counter: number) {
// logged as [COMPONENT_STORE][BASIC_COUNTER] CUSTOM_SET_STATE_NAME
this.store.setState({ counter }, 'CUSTOM_SET_STATE_NAME');
}
}
patchState
Patch a part of the state. Like setState it accepts a custom action name as the second argument.
export class AppComponent {
private storeFactory = inject(StoreFactory);
private store = this.storeFactory.createComponentStore<MyState>({
storeName: 'BASIC_COUNTER',
defaultState: { counter: 0 },
});
patch(counter: number) {
this.store.patchState({ counter });
}
patchWithCustomAction(counter: number) {
this.store.patchState({ counter }, 'CUSTOM_PATCH_STATE_NAME');
}
// an updater function receives the current state
increment() {
this.store.patchState(({ counter }) => ({ counter: counter + 1 }), 'INCREMENT');
}
}
createEffect
To use createEffect, install @ngrx/effects and add provideEffects([]) to your ApplicationConfig.
import { inject, Injectable, OnDestroy } from '@angular/core';
import { StoreFactory } from '@gernsdorfer/ngrx-lite';
import { ofType } from '@ngrx/effects';
import { createAction } from '@ngrx/store';
import { tap } from 'rxjs';
export interface MyState {
counter: number;
}
export const resetAction = createAction('reset');
@Injectable()
export class MyStore implements OnDestroy {
private storeFactory = inject(StoreFactory);
private store = this.storeFactory.createComponentStore<MyState>({
storeName: 'BASIC_COUNTER',
defaultState: { counter: 0 },
});
reset = this.store
// create an effect
.createEffect((action) =>
action.pipe(
// filter for actions
ofType(resetAction),
// change your state
tap(() => this.store.setState({ counter: 0 }, 'RESET')),
),
);
ngOnDestroy() {
this.store.ngOnDestroy();
}
}
It's necessary to destroy your store after your component is destroyed, to stop the created effect.
Call ngOnDestroy on the store.
onActions
Listen for custom actions to execute your business logic.
import { inject, Injectable } from '@angular/core';
import { StoreFactory } from '@gernsdorfer/ngrx-lite';
import { createAction } from '@ngrx/store';
export const resetAction = createAction('reset');
@Injectable()
export class MyStore {
private storeFactory = inject(StoreFactory);
private store = this.storeFactory.createComponentStore<MyState>({
storeName: 'BASIC_COUNTER',
defaultState: { counter: 0 },
});
onReset = this.store.onActions([resetAction]);
}
export class AppComponent {
private myStore = inject(MyStore);
resetEffect = this.myStore.onReset(() => console.log('Reset was triggered'));
}