Angular Snippets

Global NgRx State and NgRx Component Store

angular ngrx state

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 {}
Back to snippets