Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Why State is the Most Important Part of Your An...

Why State is the Most Important Part of Your Angular Application

State is the foundation of every modern Angular application. A well-structured state management strategy determines not only how data flows through an application but also how scalable, maintainable, and performant it becomes. Without proper state management, applications quickly become hard to debug, difficult to scale, and prone to inconsistencies. This talk explores why state is the most crucial part of an Angular application, how to choose the right state management approach, and what common pitfalls to avoid. Whether using NgRx, Akita, Signals, or a simple service-based approach, understanding and structuring state effectively is the key to long-term success.

Avatar for Fabian Gosebrink

Fabian Gosebrink

June 20, 2025
Tweet

More Decks by Fabian Gosebrink

Other Decks in Programming

Transcript

  1. @Component({ /* ... */ }) export class ProductsComponent { private

    readonly productsService = inject(ProductsService); private readonly checkoutService = inject(CheckoutService); products: Product[] = []; this.productsService.loadProducts() .subscribe((products) => this.products = products); onCartClicked(product: Product): void { this.checkoutService.addToCart(product).subscribe(() => { this.toastrService.success('Item Added to Cart'); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  2. @Component({ /* ... */ }) export class ProductsComponent { private

    readonly productsService = inject(ProductsService); private readonly checkoutService = inject(CheckoutService); products: Product[] = []; this.productsService.loadProducts() .subscribe((products) => this.products = products); onCartClicked(product: Product): void { this.checkoutService.addToCart(product).subscribe(() => { this.toastrService.success('Item Added to Cart'); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private readonly productsService = inject(ProductsService); products: Product[] = []; this.productsService.loadProducts() .subscribe((products) => this.products = products); @Component({ /* ... */ }) 1 export class ProductsComponent { 2 3 private readonly checkoutService = inject(CheckoutService); 4 5 6 7 8 9 10 onCartClicked(product: Product): void { 11 this.checkoutService.addToCart(product).subscribe(() => { 12 this.toastrService.success('Item Added to Cart'); 13 }); 14 } 15 } 16
  3. @Component({ /* ... */ }) export class ProductsComponent { private

    readonly productsService = inject(ProductsService); private readonly checkoutService = inject(CheckoutService); products: Product[] = []; this.productsService.loadProducts() .subscribe((products) => this.products = products); onCartClicked(product: Product): void { this.checkoutService.addToCart(product).subscribe(() => { this.toastrService.success('Item Added to Cart'); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private readonly productsService = inject(ProductsService); products: Product[] = []; this.productsService.loadProducts() .subscribe((products) => this.products = products); @Component({ /* ... */ }) 1 export class ProductsComponent { 2 3 private readonly checkoutService = inject(CheckoutService); 4 5 6 7 8 9 10 onCartClicked(product: Product): void { 11 this.checkoutService.addToCart(product).subscribe(() => { 12 this.toastrService.success('Item Added to Cart'); 13 }); 14 } 15 } 16 private readonly checkoutService = inject(CheckoutService); onCartClicked(product: Product): void { this.checkoutService.addToCart(product).subscribe(() => { this.toastrService.success('Item Added to Cart'); }); @Component({ /* ... */ }) 1 export class ProductsComponent { 2 private readonly productsService = inject(ProductsService); 3 4 5 products: Product[] = []; 6 7 this.productsService.loadProducts() 8 .subscribe((products) => this.products = products); 9 10 11 12 13 14 } 15 } 16
  4. export class CheckoutService { readonly #cartProductsChanged = new Subject<Product[]>(); cartProductsChanged

    = this.#cartProductsChanged.asObservable(); addToCart(product: Product) { return this.#http.post<Product[]>(this.#baseUrl, product) .pipe(map((products) => { this.#cartProductsChanged.next(products); return products; }), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  5. export class CheckoutService { readonly #cartProductsChanged = new Subject<Product[]>(); cartProductsChanged

    = this.#cartProductsChanged.asObservable(); addToCart(product: Product) { return this.#http.post<Product[]>(this.#baseUrl, product) .pipe(map((products) => { this.#cartProductsChanged.next(products); return products; }), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 readonly #cartProductsChanged = new Subject<Product[]>(); cartProductsChanged = this.#cartProductsChanged.asObservable(); this.#cartProductsChanged.next(products); export class CheckoutService { 1 2 3 4 addToCart(product: Product) { 5 return this.#http.post<Product[]>(this.#baseUrl, product) 6 .pipe(map((products) => { 7 8 9 return products; 10 }), 11 ); 12 } 13 } 14
  6. @Component({ template: ` <app-header [cartProductsCount]="cartProductsCount()" /> `, }) export class

    ShellComponent implements OnInit { cartProductsCount = signal(0); private readonly checkoutService = inject(CheckoutService); ngOnInit() { this.checkoutService.getCartProducts().subscribe((products) => { this.cartProductsCount.set(products.length); }); this.checkoutService.cartProductsChanged.subscribe((products) => { this.cartProductsCount.set(products.length); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
  7. @Component({ template: ` <app-header [cartProductsCount]="cartProductsCount()" /> `, }) export class

    ShellComponent implements OnInit { cartProductsCount = signal(0); private readonly checkoutService = inject(CheckoutService); ngOnInit() { this.checkoutService.getCartProducts().subscribe((products) => { this.cartProductsCount.set(products.length); }); this.checkoutService.cartProductsChanged.subscribe((products) => { this.cartProductsCount.set(products.length); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <app-header [cartProductsCount]="cartProductsCount()" /> cartProductsCount = signal(0); @Component({ 1 template: ` 2 3 `, 4 }) 5 export class ShellComponent implements OnInit { 6 7 private readonly checkoutService = inject(CheckoutService); 8 9 ngOnInit() { 10 this.checkoutService.getCartProducts().subscribe((products) => { 11 this.cartProductsCount.set(products.length); 12 }); 13 14 this.checkoutService.cartProductsChanged.subscribe((products) => { 15 this.cartProductsCount.set(products.length); 16 }); 17 } 18 } 19
  8. @Component({ template: ` <app-header [cartProductsCount]="cartProductsCount()" /> `, }) export class

    ShellComponent implements OnInit { cartProductsCount = signal(0); private readonly checkoutService = inject(CheckoutService); ngOnInit() { this.checkoutService.getCartProducts().subscribe((products) => { this.cartProductsCount.set(products.length); }); this.checkoutService.cartProductsChanged.subscribe((products) => { this.cartProductsCount.set(products.length); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <app-header [cartProductsCount]="cartProductsCount()" /> cartProductsCount = signal(0); @Component({ 1 template: ` 2 3 `, 4 }) 5 export class ShellComponent implements OnInit { 6 7 private readonly checkoutService = inject(CheckoutService); 8 9 ngOnInit() { 10 this.checkoutService.getCartProducts().subscribe((products) => { 11 this.cartProductsCount.set(products.length); 12 }); 13 14 this.checkoutService.cartProductsChanged.subscribe((products) => { 15 this.cartProductsCount.set(products.length); 16 }); 17 } 18 } 19 this.checkoutService.getCartProducts().subscribe((products) => { this.cartProductsCount.set(products.length); }); @Component({ 1 template: ` 2 <app-header [cartProductsCount]="cartProductsCount()" /> 3 `, 4 }) 5 export class ShellComponent implements OnInit { 6 cartProductsCount = signal(0); 7 private readonly checkoutService = inject(CheckoutService); 8 9 ngOnInit() { 10 11 12 13 14 this.checkoutService.cartProductsChanged.subscribe((products) => { 15 this.cartProductsCount.set(products.length); 16 }); 17 } 18 } 19
  9. @Component({ template: ` <app-header [cartProductsCount]="cartProductsCount()" /> `, }) export class

    ShellComponent implements OnInit { cartProductsCount = signal(0); private readonly checkoutService = inject(CheckoutService); ngOnInit() { this.checkoutService.getCartProducts().subscribe((products) => { this.cartProductsCount.set(products.length); }); this.checkoutService.cartProductsChanged.subscribe((products) => { this.cartProductsCount.set(products.length); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <app-header [cartProductsCount]="cartProductsCount()" /> cartProductsCount = signal(0); @Component({ 1 template: ` 2 3 `, 4 }) 5 export class ShellComponent implements OnInit { 6 7 private readonly checkoutService = inject(CheckoutService); 8 9 ngOnInit() { 10 this.checkoutService.getCartProducts().subscribe((products) => { 11 this.cartProductsCount.set(products.length); 12 }); 13 14 this.checkoutService.cartProductsChanged.subscribe((products) => { 15 this.cartProductsCount.set(products.length); 16 }); 17 } 18 } 19 this.checkoutService.getCartProducts().subscribe((products) => { this.cartProductsCount.set(products.length); }); @Component({ 1 template: ` 2 <app-header [cartProductsCount]="cartProductsCount()" /> 3 `, 4 }) 5 export class ShellComponent implements OnInit { 6 cartProductsCount = signal(0); 7 private readonly checkoutService = inject(CheckoutService); 8 9 ngOnInit() { 10 11 12 13 14 this.checkoutService.cartProductsChanged.subscribe((products) => { 15 this.cartProductsCount.set(products.length); 16 }); 17 } 18 } 19 this.checkoutService.cartProductsChanged.subscribe((products) => { this.cartProductsCount.set(products.length); }); @Component({ 1 template: ` 2 <app-header [cartProductsCount]="cartProductsCount()" /> 3 `, 4 }) 5 export class ShellComponent implements OnInit { 6 cartProductsCount = signal(0); 7 private readonly checkoutService = inject(CheckoutService); 8 9 ngOnInit() { 10 this.checkoutService.getCartProducts().subscribe((products) => { 11 this.cartProductsCount.set(products.length); 12 }); 13 14 15 16 17 } 18 } 19
  10. @Component({ /* ... */ }) export class CheckoutComponent implements OnInit

    { // ... cartProducts = signal<Product[]>([]); totalAmount = signal(0); ngOnInit(): void { merge( this.checkoutService.getCartProducts(), this.checkoutService.cartProductsChanged, ).subscribe((products) => { this.cartProducts.set(products); const totalAmount = this.calculateTotalAmount(products); this.totalAmount.set(totalAmount); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  11. @Component({ /* ... */ }) export class CheckoutComponent implements OnInit

    { // ... cartProducts = signal<Product[]>([]); totalAmount = signal(0); ngOnInit(): void { merge( this.checkoutService.getCartProducts(), this.checkoutService.cartProductsChanged, ).subscribe((products) => { this.cartProducts.set(products); const totalAmount = this.calculateTotalAmount(products); this.totalAmount.set(totalAmount); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cartProducts = signal<Product[]>([]); totalAmount = signal(0); @Component({ /* ... */ }) 1 export class CheckoutComponent implements OnInit { 2 // ... 3 4 5 6 ngOnInit(): void { 7 merge( 8 this.checkoutService.getCartProducts(), 9 this.checkoutService.cartProductsChanged, 10 ).subscribe((products) => { 11 this.cartProducts.set(products); 12 const totalAmount = this.calculateTotalAmount(products); 13 this.totalAmount.set(totalAmount); 14 }); 15 } 16 } 17
  12. @Component({ /* ... */ }) export class CheckoutComponent implements OnInit

    { // ... cartProducts = signal<Product[]>([]); totalAmount = signal(0); ngOnInit(): void { merge( this.checkoutService.getCartProducts(), this.checkoutService.cartProductsChanged, ).subscribe((products) => { this.cartProducts.set(products); const totalAmount = this.calculateTotalAmount(products); this.totalAmount.set(totalAmount); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cartProducts = signal<Product[]>([]); totalAmount = signal(0); @Component({ /* ... */ }) 1 export class CheckoutComponent implements OnInit { 2 // ... 3 4 5 6 ngOnInit(): void { 7 merge( 8 this.checkoutService.getCartProducts(), 9 this.checkoutService.cartProductsChanged, 10 ).subscribe((products) => { 11 this.cartProducts.set(products); 12 const totalAmount = this.calculateTotalAmount(products); 13 this.totalAmount.set(totalAmount); 14 }); 15 } 16 } 17 merge( this.checkoutService.getCartProducts(), this.checkoutService.cartProductsChanged, @Component({ /* ... */ }) 1 export class CheckoutComponent implements OnInit { 2 // ... 3 cartProducts = signal<Product[]>([]); 4 totalAmount = signal(0); 5 6 ngOnInit(): void { 7 8 9 10 ).subscribe((products) => { 11 this.cartProducts.set(products); 12 const totalAmount = this.calculateTotalAmount(products); 13 this.totalAmount.set(totalAmount); 14 }); 15 } 16 } 17
  13. @Component({ /* ... */ }) export class CheckoutComponent implements OnInit

    { // ... cartProducts = signal<Product[]>([]); totalAmount = signal(0); ngOnInit(): void { merge( this.checkoutService.getCartProducts(), this.checkoutService.cartProductsChanged, ).subscribe((products) => { this.cartProducts.set(products); const totalAmount = this.calculateTotalAmount(products); this.totalAmount.set(totalAmount); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cartProducts = signal<Product[]>([]); totalAmount = signal(0); @Component({ /* ... */ }) 1 export class CheckoutComponent implements OnInit { 2 // ... 3 4 5 6 ngOnInit(): void { 7 merge( 8 this.checkoutService.getCartProducts(), 9 this.checkoutService.cartProductsChanged, 10 ).subscribe((products) => { 11 this.cartProducts.set(products); 12 const totalAmount = this.calculateTotalAmount(products); 13 this.totalAmount.set(totalAmount); 14 }); 15 } 16 } 17 merge( this.checkoutService.getCartProducts(), this.checkoutService.cartProductsChanged, @Component({ /* ... */ }) 1 export class CheckoutComponent implements OnInit { 2 // ... 3 cartProducts = signal<Product[]>([]); 4 totalAmount = signal(0); 5 6 ngOnInit(): void { 7 8 9 10 ).subscribe((products) => { 11 this.cartProducts.set(products); 12 const totalAmount = this.calculateTotalAmount(products); 13 this.totalAmount.set(totalAmount); 14 }); 15 } 16 } 17 ).subscribe((products) => { this.cartProducts.set(products); const totalAmount = this.calculateTotalAmount(products); this.totalAmount.set(totalAmount); }); @Component({ /* ... */ }) 1 export class CheckoutComponent implements OnInit { 2 // ... 3 cartProducts = signal<Product[]>([]); 4 totalAmount = signal(0); 5 6 ngOnInit(): void { 7 merge( 8 this.checkoutService.getCartProducts(), 9 this.checkoutService.cartProductsChanged, 10 11 12 13 14 15 } 16 } 17
  14. Header/Shell - Reads State Manipulate State /products Has State Checkout

    Service Reads State /checkout Manipulate State Reads State
  15. @Injectable({ providedIn: 'root' }) export class CheckoutService { readonly cartProducts

    = signal<Product[]>([]); readonly cartProductCount = computed(() => this.cartProducts().length); readonly totalAmount = computed(() => this.cartProducts() .reduce((acc: number, prev) => acc + prev.price, 0), ); addToCart(product: Product) { // ... } // more functions } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  16. @Injectable({ providedIn: 'root' }) export class CheckoutService { readonly cartProducts

    = signal<Product[]>([]); readonly cartProductCount = computed(() => this.cartProducts().length); readonly totalAmount = computed(() => this.cartProducts() .reduce((acc: number, prev) => acc + prev.price, 0), ); addToCart(product: Product) { // ... } // more functions } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 readonly cartProducts = signal<Product[]>([]); readonly cartProductCount = computed(() => this.cartProducts().length); readonly totalAmount = computed(() => this.cartProducts() .reduce((acc: number, prev) => acc + prev.price, 0), ); @Injectable({ providedIn: 'root' }) 1 export class CheckoutService { 2 3 4 5 6 7 8 9 10 11 12 addToCart(product: Product) { 13 // ... 14 } 15 16 // more functions 17 } 18
  17. @Component({ template: ` <app-header [cartProductsCount]="cartProductsCount()" /> `, }) export class

    ShellComponent implements OnInit { cartProductsCount = signal(0); private readonly checkoutService = inject(CheckoutService); ngOnInit() { this.checkoutService.getCartProducts().subscribe((products) => { this.cartProductsCount.set(products.length); }); this.checkoutService.cartProductsChanged.subscribe((products) => { this.cartProductsCount.set(products.length); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
  18. @Component({ template: ` <app-header [cartProductsCount]="cartProductsCount()" /> `, }) export class

    ShellComponent implements OnInit { readonly cartProductsCount = inject(CheckoutService).cartProductCount; } 1 2 3 4 5 6 7 8
  19. @Component({ /* ... */ }) export class CheckoutComponent implements OnInit

    { // ... cartProducts = signal<Product[]>([]); totalAmount = signal(0); ngOnInit(): void { merge( this.checkoutService.getCartProducts(), this.checkoutService.cartProductsChanged, ).subscribe((products) => { this.cartProducts.set(products); const totalAmount = this.calculateTotalAmount(products); this.totalAmount.set(totalAmount); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  20. @Component({ /* ... */ }) export class CheckoutComponent implements OnInit

    { readonly #checkoutService = inject(CheckoutService); readonly cartProducts = this.#checkoutService.cartProducts; readonly totalAmount = this.#checkoutService.totalAmount; ngOnInit(): void { this.checkoutService.getCartProducts(); } } 1 2 3 4 5 6 7 8 9 10 11
  21. src/ └── app/ ├── features/ │ ├── checkout/ │ │

    └── ... │ └── products/ │ └── ... └── shared/ └── auth/ └── ... 1 2 3 4 5 6 7 8 9 10
  22. { "product": { // ... }, "checkout": { // ...

    }, "shared": { ... }, } 1 2 3 4 5 6 7 8 9 10 11 export const APP_ROUTES: Routes = [ { path: 'product', loadChildren: () => // ... }, { path: 'checkout', loadChildren: () => // ... }, ]; 1 2 3 4 5 6 7 8 9 10
  23. Service A Service B Service C Service C ... Feature

    State Component State Component State
  24. Service A Service B Service C Service C ... WebSockets

    Component State Component State Feature State
  25. @Injectable({ providedIn: 'root' }) export class CheckoutService { readonly #baseUrl

    = 'http://localhost:3000/cart/'; readonly #http = inject(HttpClient); addToCart(product: Product) { return this.#http.post<Product[]>(this.#baseUrl, product); } getCartProducts() { return this.#http.get<Product[]>(this.#baseUrl); } removeFromCart(index: number) { return this.#http.delete(this.#baseUrl + index); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  26. export const CheckoutStore = signalStore( { providedIn: 'root' }, withState<CheckoutState>({

    products: [] as Product[]}), withComputed((store) => ({ cartProductsCount: computed(() => store.products().length), totalAmount: computed(() => { /* ... */ }), })), withMethods((store, checkoutService = inject(CheckoutService)) => ({ loadAll: rxMethod<void>( exhaustMap(() => checkoutService.getCartProducts().pipe( tapResponse({ next: (products) => patchState(store, { products }), }), ), ), ), // ... })), withHooks({ onInit(store) { store.loadAll(); }, }), ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  27. export const CheckoutStore = signalStore( { providedIn: 'root' }, withState<CheckoutState>({

    products: [] as Product[]}), withComputed((store) => ({ cartProductsCount: computed(() => store.products().length), totalAmount: computed(() => { /* ... */ }), })), withMethods((store, checkoutService = inject(CheckoutService)) => ({ loadAll: rxMethod<void>( exhaustMap(() => checkoutService.getCartProducts().pipe( tapResponse({ next: (products) => patchState(store, { products }), }), ), ), ), // ... })), withHooks({ onInit(store) { store.loadAll(); }, }), ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 withState<CheckoutState>({ products: [] as Product[]}), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 3 withComputed((store) => ({ 4 cartProductsCount: computed(() => store.products().length), 5 totalAmount: computed(() => { /* ... */ }), 6 })), 7 withMethods((store, checkoutService = inject(CheckoutService)) => ({ 8 loadAll: rxMethod<void>( 9 exhaustMap(() => 10 checkoutService.getCartProducts().pipe( 11 tapResponse({ 12 next: (products) => patchState(store, { products }), 13 }), 14 ), 15 ), 16 ), 17 // ... 18 })), 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25
  28. export const CheckoutStore = signalStore( { providedIn: 'root' }, withState<CheckoutState>({

    products: [] as Product[]}), withComputed((store) => ({ cartProductsCount: computed(() => store.products().length), totalAmount: computed(() => { /* ... */ }), })), withMethods((store, checkoutService = inject(CheckoutService)) => ({ loadAll: rxMethod<void>( exhaustMap(() => checkoutService.getCartProducts().pipe( tapResponse({ next: (products) => patchState(store, { products }), }), ), ), ), // ... })), withHooks({ onInit(store) { store.loadAll(); }, }), ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 withState<CheckoutState>({ products: [] as Product[]}), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 3 withComputed((store) => ({ 4 cartProductsCount: computed(() => store.products().length), 5 totalAmount: computed(() => { /* ... */ }), 6 })), 7 withMethods((store, checkoutService = inject(CheckoutService)) => ({ 8 loadAll: rxMethod<void>( 9 exhaustMap(() => 10 checkoutService.getCartProducts().pipe( 11 tapResponse({ 12 next: (products) => patchState(store, { products }), 13 }), 14 ), 15 ), 16 ), 17 // ... 18 })), 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25 withComputed((store) => ({ cartProductsCount: computed(() => store.products().length), totalAmount: computed(() => { /* ... */ }), })), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 withState<CheckoutState>({ products: [] as Product[]}), 3 4 5 6 7 withMethods((store, checkoutService = inject(CheckoutService)) => ({ 8 loadAll: rxMethod<void>( 9 exhaustMap(() => 10 checkoutService.getCartProducts().pipe( 11 tapResponse({ 12 next: (products) => patchState(store, { products }), 13 }), 14 ), 15 ), 16 ), 17 // ... 18 })), 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25
  29. export const CheckoutStore = signalStore( { providedIn: 'root' }, withState<CheckoutState>({

    products: [] as Product[]}), withComputed((store) => ({ cartProductsCount: computed(() => store.products().length), totalAmount: computed(() => { /* ... */ }), })), withMethods((store, checkoutService = inject(CheckoutService)) => ({ loadAll: rxMethod<void>( exhaustMap(() => checkoutService.getCartProducts().pipe( tapResponse({ next: (products) => patchState(store, { products }), }), ), ), ), // ... })), withHooks({ onInit(store) { store.loadAll(); }, }), ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 withState<CheckoutState>({ products: [] as Product[]}), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 3 withComputed((store) => ({ 4 cartProductsCount: computed(() => store.products().length), 5 totalAmount: computed(() => { /* ... */ }), 6 })), 7 withMethods((store, checkoutService = inject(CheckoutService)) => ({ 8 loadAll: rxMethod<void>( 9 exhaustMap(() => 10 checkoutService.getCartProducts().pipe( 11 tapResponse({ 12 next: (products) => patchState(store, { products }), 13 }), 14 ), 15 ), 16 ), 17 // ... 18 })), 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25 withComputed((store) => ({ cartProductsCount: computed(() => store.products().length), totalAmount: computed(() => { /* ... */ }), })), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 withState<CheckoutState>({ products: [] as Product[]}), 3 4 5 6 7 withMethods((store, checkoutService = inject(CheckoutService)) => ({ 8 loadAll: rxMethod<void>( 9 exhaustMap(() => 10 checkoutService.getCartProducts().pipe( 11 tapResponse({ 12 next: (products) => patchState(store, { products }), 13 }), 14 ), 15 ), 16 ), 17 // ... 18 })), 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25 withMethods((store, checkoutService = inject(CheckoutService)) => ({ loadAll: rxMethod<void>( exhaustMap(() => checkoutService.getCartProducts().pipe( tapResponse({ next: (products) => patchState(store, { products }), }), ), ), ), // ... })), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 withState<CheckoutState>({ products: [] as Product[]}), 3 withComputed((store) => ({ 4 cartProductsCount: computed(() => store.products().length), 5 totalAmount: computed(() => { /* ... */ }), 6 })), 7 8 9 10 11 12 13 14 15 16 17 18 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25
  30. export const CheckoutStore = signalStore( { providedIn: 'root' }, withState<CheckoutState>({

    products: [] as Product[]}), withComputed((store) => ({ cartProductsCount: computed(() => store.products().length), totalAmount: computed(() => { /* ... */ }), })), withMethods((store, checkoutService = inject(CheckoutService)) => ({ loadAll: rxMethod<void>( exhaustMap(() => checkoutService.getCartProducts().pipe( tapResponse({ next: (products) => patchState(store, { products }), }), ), ), ), // ... })), withHooks({ onInit(store) { store.loadAll(); }, }), ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 withState<CheckoutState>({ products: [] as Product[]}), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 3 withComputed((store) => ({ 4 cartProductsCount: computed(() => store.products().length), 5 totalAmount: computed(() => { /* ... */ }), 6 })), 7 withMethods((store, checkoutService = inject(CheckoutService)) => ({ 8 loadAll: rxMethod<void>( 9 exhaustMap(() => 10 checkoutService.getCartProducts().pipe( 11 tapResponse({ 12 next: (products) => patchState(store, { products }), 13 }), 14 ), 15 ), 16 ), 17 // ... 18 })), 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25 withComputed((store) => ({ cartProductsCount: computed(() => store.products().length), totalAmount: computed(() => { /* ... */ }), })), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 withState<CheckoutState>({ products: [] as Product[]}), 3 4 5 6 7 withMethods((store, checkoutService = inject(CheckoutService)) => ({ 8 loadAll: rxMethod<void>( 9 exhaustMap(() => 10 checkoutService.getCartProducts().pipe( 11 tapResponse({ 12 next: (products) => patchState(store, { products }), 13 }), 14 ), 15 ), 16 ), 17 // ... 18 })), 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25 withMethods((store, checkoutService = inject(CheckoutService)) => ({ loadAll: rxMethod<void>( exhaustMap(() => checkoutService.getCartProducts().pipe( tapResponse({ next: (products) => patchState(store, { products }), }), ), ), ), // ... })), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 withState<CheckoutState>({ products: [] as Product[]}), 3 withComputed((store) => ({ 4 cartProductsCount: computed(() => store.products().length), 5 totalAmount: computed(() => { /* ... */ }), 6 })), 7 8 9 10 11 12 13 14 15 16 17 18 19 withHooks({ 20 onInit(store) { 21 store.loadAll(); 22 }, 23 }), 24 ); 25 withHooks({ onInit(store) { store.loadAll(); }, }), export const CheckoutStore = signalStore( 1 { providedIn: 'root' }, 2 withState<CheckoutState>({ products: [] as Product[]}), 3 withComputed((store) => ({ 4 cartProductsCount: computed(() => store.products().length), 5 totalAmount: computed(() => { /* ... */ }), 6 })), 7 withMethods((store, checkoutService = inject(CheckoutService)) => ({ 8 loadAll: rxMethod<void>( 9 exhaustMap(() => 10 checkoutService.getCartProducts().pipe( 11 tapResponse({ 12 next: (products) => patchState(store, { products }), 13 }), 14 ), 15 ), 16 ), 17 // ... 18 })), 19 20 21 22 23 24 ); 25
  31. @Component({ template: ` <app-header [cartProductsCount]="store.cartProductsCount()" /> `, }) export class

    ShellComponent { readonly store = inject(CheckoutStore); } 1 2 3 4 5 6 7 8
  32. @Component({ template: ` @for ( productCategory of store.productsByCategories(); track ...)

    { //... } `, providers: [ProductsStore], }) export class ProductsComponent { readonly store = inject(ProductsStore); // using store if needed } 1 2 3 4 5 6 7 8 9 10 11 12 13