NgRx SignalStore is a modern, signal-based library for state management.
1npm install @ngrx/signals1import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
2import { computed, inject } from '@angular/core';
3
4interface SamuraiState {
5 samurai: Samurai[];
6 loading: boolean;
7 filter: string;
8}
9
10const initialState: SamuraiState = {
11 samurai: [],
12 loading: false,
13 filter: ''
14};
15
16export const SamuraiStore = signalStore(
17 { providedIn: 'root' },
18
19 // State
20 withState(initialState),
21
22 // Computed signals
23 withComputed((store) => ({
24 filteredSamurai: computed(() => {
25 const filter = store.filter().toLowerCase();
26 return store.samurai().filter(s =>
27 s.name.toLowerCase().includes(filter)
28 );
29 }),
30 count: computed(() => store.samurai().length)
31 })),
32
33 // Methods (actions)
34 withMethods((store, http = inject(HttpClient)) => ({
35 loadSamurai(): void {
36 patchState(store, { loading: true });
37
38 http.get<Samurai[]>('/api/samurai').subscribe({
39 next: (samurai) => patchState(store, { samurai, loading: false }),
40 error: () => patchState(store, { loading: false })
41 });
42 },
43
44 setFilter(filter: string): void {
45 patchState(store, { filter });
46 },
47
48 addSamurai(samurai: Samurai): void {
49 patchState(store, (state) => ({
50 samurai: [...state.samurai, samurai]
51 }));
52 }
53 }))
54);
55
56// Usage in a component
57@Component({
58 template: \`
59 <input (input)="store.setFilter($any($event.target).value)">
60 @for (s of store.filteredSamurai(); track s.id) {
61 <div>{{ s.name }}</div>
62 }
63 \`
64})
65export class SamuraiListComponent {
66 store = inject(SamuraiStore);
67
68 constructor() {
69 this.store.loadSamurai();
70 }
71}