An example of a simple global NgRx Store that is used in a ComponentStore that reacts to global state changes and manipulates the rest.
Set up a global NgRx Store with Effects.
import { createAction, createFeature, createReducer, on } from "@ngrx/store";
import { createEffect } from "@ngrx/effects";
import { interval, map } from "rxjs";
interface CounterState {
counter: number;
}
const initialCounterState: CounterState = {
counter: 0,
};
export const incrementCounter = createAction(
"[Angular Snippets Example] Increment Counter"
);
export const counterState = createFeature({
name: "counter",
reducer: createReducer(
initialCounterState,
on(incrementCounter, (state) => ({
...state,
counter: state.counter + 1,
}))
),
});
export const { selectCounter } = counterState;
export const incrementCounterEffect = createEffect(
() => interval(1000).pipe(map(() => incrementCounter())),
{ functional: true }
);
Add your global state to the application
import { bootstrapApplication } from "@angular/platform-browser";
import { AppComponent } from "./app/app.component";
import { provideState, provideStore } from "@ngrx/store";
import {
counterState,
incrementCounterEffect,
} from "./app/global-state-in-component-store";
import { provideEffects } from "@ngrx/effects";
bootstrapApplication(AppComponent, {
providers: [
provideStore({}),
provideState(counterState),
provideEffects({ incrementCounterEffect }),
],
}).catch((err) => console.error(err));
Pull the global state into a component store
import { Component, inject, Injectable } from "@angular/core";
import { ComponentStore } from "@ngrx/component-store";
import { Store } from "@ngrx/store";
import { Observable, tap } from "rxjs";
import { AsyncPipe } from "@angular/common";
interface MyState {
counter: number;
}
@Injectable({ providedIn: "root" })
export class ComponentStoreWithGlobalState extends ComponentStore<MyState> {
readonly counter$ = this.select((state) => state.counter);
private readonly store = inject(Store);
private readonly setCounter = this.updater((state, counter: number) => ({
...state,
counter,
}));
private readonly multiplyGlobalStateByTwo = this.effect(
(origin$: Observable<number>) =>
origin$.pipe(tap((counter) => this.setCounter(counter * 2)))
);
constructor() {
super({ counter: 0 });
this.multiplyGlobalStateByTwo(this.store.select(selectCounter));
}
}
@Component({
selector: "component-store-with-global-state",
standalone: true,
providers: [ComponentStoreWithGlobalState],
imports: [AsyncPipe],
template: ` <div>{{ counter$ | async }}</div>`,
})
export class ComponentStoreWithGlobalStateComponent {
readonly store = inject(ComponentStoreWithGlobalState);
readonly counter$ = this.store.counter$;
}
Use the component
import { Component } from "@angular/core";
import { ComponentStoreWithGlobalStateComponent } from "./global-state-in-component-store";
@Component({
standalone: true,
selector: "angular-snippet-examples-root",
template: `
<component-store-with-global-state></component-store-with-global-state>
`,
styles: [],
imports: [ComponentStoreWithGlobalStateComponent],
})
export class AppComponent {}