From 3850a98b53d6b6ef1004bc4ca6e2a8658b7cc4ee Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:41:49 +0100 Subject: [PATCH] docs: add breaking changes to v19 migration (#4620) --- .../ngrx.io/content/guide/migration/v19.md | 144 +++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/projects/ngrx.io/content/guide/migration/v19.md b/projects/ngrx.io/content/guide/migration/v19.md index 0c8013b9f4..5e93ae991c 100644 --- a/projects/ngrx.io/content/guide/migration/v19.md +++ b/projects/ngrx.io/content/guide/migration/v19.md @@ -21,4 +21,146 @@ Version 19 has the minimum version requirements: ## Breaking changes -TODO +### Signals + +#### Throw error in dev mode on state mutation + +The `patchState` method applies a deep freeze on the state in dev mode. +If you try to update the state directly, it will throw an error in dev mode. + +BEFORE: + +```ts +const userState = signalState(initialState); +patchState(userState, (state) => { + // mutable change which went through + state.user.firstName = 'mutable change'; + return state; +}); +``` + +AFTER: + +```ts +const userState = signalState(initialState); +patchState(userState, (state) => { + // mutable change throws in dev mode + state.user.firstName = 'mutable change'; + return state; +}); +``` + +To fix the error, update the state in an immutable way. + +```ts +const userState = signalState(initialState); +patchState(userState, (state) => { + return { + ...state, + user: { + ...state.user, + // immutable change which went through + firstName: 'immutable change', + }, + }; +}); +``` + +#### `computed` is replaced with `props` + +To support more cases, the `props` property is added to `signalStoreFeature`, which replaces the existing `computed` property. +This change has an ng-update schematic that automatically updates your code. + +- The `computed` property in the `SignalStoreFeature` type is renamed to `props`. +- The `computed` property in the `signalStoreFeature` method is renamed to `props`. +- The `EntityComputed` and `NamedEntityComputed` types in the `entities` plugin are renamed to `EntityProps` and `NamedEntityProps`. + +BEFORE: + +```ts +import { computed, Signal } from '@angular/core'; +import { + signalStoreFeature, + SignalStoreFeature, + type, + withComputed, +} from '@ngrx/signals'; +import { EntityComputed } from '@ngrx/signals/entities'; + +export function withTotalEntities(): SignalStoreFeature< + { state: {}, computed: EntityComputed, methods: {} }, + { state: {}, computed: { total: Signal }, methods: {} }, +> { + return signalStoreFeature( + { computed: type>() }, + withComputed(({ entities }) => ({ + total: computed(() => entities().length), + })), + ); +} +``` + +AFTER: + +```ts +import { computed, Signal } from '@angular/core'; +import { + signalStoreFeature, + SignalStoreFeature, + type, + withComputed, +} from '@ngrx/signals'; +import { EntityProps } from '@ngrx/signals/entities'; + +export function withTotalEntities(): SignalStoreFeature< + { state: {}, props: EntityProps, methods: {} }, + { state: {}, props: { total: Signal }, methods: {} }, +> { + return signalStoreFeature( + { props: type>() }, + withComputed(({ entities }) => ({ + total: computed(() => entities().length), + })), + ); +} +``` + +#### Rename `rxMethod.unsubscribe()` to `rxMethod.destroy()` + +The `unsubscribe` method from `rxMethod` is renamed to `destroy`. + +BEFORE: + +```ts +const logNumber = rxMethod(tap(console.log)); + +const num1Ref = logNumber(interval(1_000)); +const num2Ref = logNumber(interval(2_000)); + +// destroy `num1Ref` after 2 seconds +setTimeout(() => num1Ref.unsubscribe(), 2_000); + +// destroy all reactive method refs after 5 seconds +setTimeout(() => logNumber.unsubscribe(), 5_000); +``` + +AFTER: + +```ts +const logNumber = rxMethod(tap(console.log)); + +const num1Ref = logNumber(interval(1_000)); +const num2Ref = logNumber(interval(2_000)); + +// destroy `num1Ref` after 2 seconds +setTimeout(() => num1Ref.destroy(), 2_000); + +// destroy all reactive method refs after 5 seconds +setTimeout(() => logNumber.destroy(), 5_000); +``` + +### Schematics + +#### Standalone is the default + +(Container) components created by the Container Schematic are now standalone by default.