#Basic state management with built-in features

5 messages · Page 1 of 1 (latest)

rancid geyser
#

I was wondering about a straightforward method to handle application state using Angular 18's built-in features. Would starting with a simple service utilizing dependency injection (DI) be a good approach?

Being new to Angular 18, I find myself a bit perplexed about managing state simply within Angular. Previous experiences with other frontend libraries often advocate for commencing with basic state management using built in functionalities (similar to useState and context in the React ecosystem).

In the Angular realm, there seems to be a reliance on RxJS even for uncomplicated state management solutions.

I created a tiny demonstration using Angular services and dependency injection: https://stackblitz.com/edit/stackblitz-starters-yfyrgb?file=src%2Fmain.ts

`import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root',
})
export class StoreService {
state = {
name: '🐈',
};

getState() {
return this.state;
}

setState(state: { name: string }) {
this.state = state;
}
}`

It covers basic things like giving components access to a global state object. However, is this approach viable? Sure, I would go with something like ImmutableJS or Immer to properly change the state. What are the drawbacks compared to using RxJS?

An angular-cli project based on @angular/animations, @angular/common, @angular/compiler, @angular/core, @angular/forms, @angular/platform-browser, @angular/platform-browser-dynamic, @angular/router, core-js, rxjs, tslib and zone.js

uneven rampart
#

The drawback is that it doesn't provide any way for a consumer of the service to know when the state has changed. To have that, you would use RxJS, or a signal.

timber patrol
#

If you don't want to 'complicate' things for simple stuff use Signal instead of RxJS

rancid geyser
#

Ok, thanks! Is it encouraged to wrap the signal with a service? Or would I just create a signal and import it into all my components?

uneven rampart
# rancid geyser Ok, thanks! Is it encouraged to wrap the signal with a service? Or would I just ...

Unless your state is some value that anything is free to update, without having any additional constraint to be checked or business logic assciated, you probably want both a read-only signal exposed by the service that anything can import and read, and methods in the service that encapsulate the state changes and are the only one who can access the writable signal from which the read-only signal is derived:

private _counter = signal(0);
public readonly counter = this._counter.asReadonly();

increment() {
  this._counter.update(c => c + 1);
}
decrement() {
  this.counter.update(c => Math.max(0, c - 1));
}

In any case, wrapping it is a service is useful to be able to provide a mock service in unit tests.