8000 fix(signals): revert the protection for state mutation in dev mode (#… · ngrx/platform@ae7922e · GitHub
[go: up one dir, main page]

Skip to content

Commit

Permalink
fix(signals): revert the protection for state mutation in dev mode (#…
Browse files Browse the repository at this point in the history
…4686)

Closes #4683
  • Loading branch information
rainerhahnekamp authored Jan 28, 2025
1 parent 44cb328 commit ae7922e
Show file tree
Hide file tree
Showing 7 changed files with 9 additions and 257 deletions.
150 changes: 0 additions & 150 deletions modules/signals/spec/deep-freeze.spec.ts

This file was deleted.

48 changes: 0 additions & 48 deletions modules/signals/src/deep-freeze.ts

This file was deleted.

3 changes: 1 addition & 2 deletions modules/signals/src/signal-state.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { signal } from '@angular/core';
import { STATE_SOURCE, WritableStateSource } from './state-source';
import { DeepSignal, toDeepSignal } from './deep-signal';
import { freezeInDevMode } from './deep-freeze';

export type SignalState<State extends object> = DeepSignal<State> &
WritableStateSource<State>;

export function signalState<State extends object>(
initialState: State
): SignalState<State> {
const stateSource = signal(freezeInDevMode(initialState as State));
const stateSource = signal(initialState as State);
const signalState = toDeepSignal(stateSource.asReadonly());
Object.defineProperty(signalState, STATE_SOURCE, {
value: stateSource,
Expand Down
10 changes: 4 additions & 6 deletions modules/signals/src/state-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
WritableSignal,
} from '@angular/core';
import { Prettify } from './ts-helpers';
import { freezeInDevMode } from './deep-freeze';

const STATE_WATCHERS = new WeakMap<Signal<object>, Array<StateWatcher<any>>>();

Expand Down Expand Up @@ -38,11 +37,10 @@ export function patchState<State extends object>(
): void {
stateSource[STATE_SOURCE].update((currentState) =>
updaters.reduce(
(nextState: State, updater) =>
freezeInDevMode({
...nextState,
...(typeof updater === 'function' ? updater(nextState) : updater),
}),
(nextState: State, updater) => ({
...nextState,
...(typeof updater === 'function' ? updater(nextState) : updater),
}),
currentState
)
);
Expand Down
11 changes: 4 additions & 7 deletions modules/signals/src/with-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
SignalStoreFeature,
SignalStoreFeatureResult,
} from './signal-store-models';
import { freezeInDevMode } from './deep-freeze';

export function withState<State extends object>(
stateFactory: () => State
Expand All @@ -36,12 +35,10 @@ export function withState<State extends object>(

assertUniqueStoreMembers(store, stateKeys);

store[STATE_SOURCE].update((currentState) =>
freezeInDevMode({
...currentState,
...state,
})
);
store[STATE_SOURCE].update((currentState) => ({
...currentState,
...state,
}));

const stateSignals = stateKeys.reduce((acc, key) => {
const sliceSignal = computed(
Expand Down
43 changes: 0 additions & 43 deletions projects/ngrx.io/content/guide/migration/v19.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,49 +23,6 @@ Version 19 has the minimum version requirements:

### 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.
Expand Down
1 change: 0 additions & 1 deletion projects/ngrx.io/content/guide/signals/signal-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ patchState(
<div class="alert is-critical">

Updaters passed to the `patchState` function must perform state updates in an immutable manner.
If a mutable change occurs to the state object, an error will be thrown in development mode.

</div>

Expand Down

0 comments on commit ae7922e

Please sign in to comment.
0