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

2025-09-05_Hold_the_Line.pdf

 2025-09-05_Hold_the_Line.pdf

Avatar for Rainer Hahnekamp

Rainer Hahnekamp

September 05, 2025
Tweet

More Decks by Rainer Hahnekamp

Other Decks in Technology

Transcript

  1. About Me... https://www.youtube.com/ @RainerHahnekamp https://www.ng-news.com https://github.com/softarc-consulting/sheriff • Rainer Hahnekamp ANGULARarchitects.io

    NgRx Team (Trusted Collaborator) • Developer / Trainer / Speaker @RainerHahnekamp Workshops NgRx • Testing • Spring • Quality
  2. Agenda • The Importance of State • Why SignalStore •

    How do we work? • Where are we? • What comes next?
  3. a b c d e State Events (Observables, Callbacks) "Event-based"

    Change Detection / Synchronization (zone.js) No State-Changing Events
  4. a b c d e State (Signals) Events (Observables, Callbacks)

    "State-based" Change Detection / Synchronization (Signals)
  5. A Comparison: State & Slices @Injectable({ providedIn: 'root' }) export

    class HolidaysStore { // State readonly #state = signal({ holidays: [] as Holiday[], favouriteIds: [] as number[], filter: { query: '', type: 0 }, }); // Slices holidays = computed(() => this.#state().holidays); favouriteIds = computed(() => this.#state().favouriteIds); filter = computed(() => this.#state().filter); } export const HolidayStore = signalStore( { providedIn: 'root' }, withState({ holidays: [] as Holiday[], favouriteIds: [] as number[], filter: { query: '', type: 0 }, }) );
  6. A Comparison: Computeds export class HolidaysStore { // Computed holidaysCount

    = computed(() => this.#state().holidays.length); } export const HolidayStore = signalStore( withComputed(({ holidays }) => ({ holidaysCount: () => holidays().length, })), );
  7. A Comparison: Methods export class HolidaysStore { // Methods readonly

    #httpClient = inject(HttpClient); async load() { const holidays = await lastValueFrom( this.#httpClient.get<Holiday[]>('/holiday'), ); this.#state.update((state) => ({ ...state, holidays })); } } export const HolidayStore = signalStore( withMethods((store, httpClient = inject(HttpClient)) => ({ async load() { const holidays = await lastValueFrom( httpClient.get<Holiday[]>('/holiday'), ); patchState(store, { holidays }); }, })) );
  8. Hold the Line • Built on top of Angular Signals

    ◦ Not create a parallel universe • Work closely with the Angular Team ◦ No Plan for a full State Management • Adapt whenever necessary • Don't break things ◦ Careful Design (takes longer) ◦ Migrations ◦ Don't provide too much
  9. • Stable Version • Features for "larger" Stores ◦ Protected

    State ◦ Encapsulation ◦ Overriding Warning Version 18
  10. Version 19 • signalMethod ◦ RxJS-less connector ◦ Explicit Tracking

    • withProps ◦ Generic Feature for adding non-standardized elements ◦ Not a state, method or computed • withFeature ◦ For Library Authors ◦ Allows Custom Features to access the calling Store • Events Plugin ◦ Optionals ◦ Redux for the SignalStore ◦ Minor Differences to @ngrx/store ◦ "One size fits all" Solution
  11. Version 20 • Support for linkedSignal ◦ Via withLinkedState ◦

    Per Slice (not the whole State) ◦ Also supports user-defined Signals • Support for resource/rxResource/httpResource ◦ PR available but on hold ◦ resource needs to be developer preview ◦ Implementation available via ngrx-toolkit
  12. withResource() • Writable only internally, read only to the outside

    • SignalStore as Resource<T> • Named Resources ◦ Along mapper functions • Further Investigation for withEntities integration
  13. NgRx Toolkit Mutations • Resource for "Changing Data" • Potential

    upcoming feature for Angular • Design Consultations with ◦ Alex Rickabaugh (Angular Core) ◦ Marko Staminirovic (NgRx) • "Mutation Mindset" • Usable outside the SignalStore