refactor(signals)!: multiple signals in STATE_SOURCE#4779
Closed
rainerhahnekamp wants to merge 1 commit intongrx:mainfrom
Closed
refactor(signals)!: multiple signals in STATE_SOURCE#4779rainerhahnekamp wants to merge 1 commit intongrx:mainfrom
STATE_SOURCE#4779rainerhahnekamp wants to merge 1 commit intongrx:mainfrom
Conversation
✅ Deploy Preview for ngrx-io ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify site configuration. |
❌ Deploy Preview for ngrx-site-v19 failed.
|
This is a necessary refactoring to support a state which allows different types of Signals, i.e. `linkedSignal` & `signal` but still presents itself as a single unit to the outside.
This commit splits the single Signal of `STATE_SOURCE`, which contains the state in the `SignalStore` and `signalState`, into multiple Signals.
An example. Given the following type:
```typescript
type User = {
firstname: string;
lastname: string;
};
```
Before, `STATE_SOURCE` would have been the following type:
```typescript
WritableSignal<User>;
```
With this change, it is:
```typescript
{
firstname: WritableSignal<string>;
lastname: WritableSignal<string>;
}
```
Most changes affect the tests which focus on the `STATE_SOURCE`. Except for one test in `signal-state.spec.ts` ('does not modify STATE_SOURCE'), all tests could be updated to assert the new behavior.
## Breaking Changes
- Any code which accesses the hidden `STATE_SOURCE` will be impacted.
- Breaking Changes to the public behavior are rare.
### different object reference for state of `STATE_SOURCE`
`STATE_SOURCE` does not keep the object reference of the initial state upon initialization.
```typescript
const initialObject = {
ngrx: 'rocks',
};
const state = signalState(initialObject);
// before
state() === initialObject; // ✅
// after
state() === initialObject; // ❌
```
### no Signal change on empty patched state
`patchState` created a clone of the state and applied the patches to the clone. That meant, if nothing was changed, the Signal still fired because of the shallow clone. Since the state Signal doesn't exist anymore, there will be no change in this case.
```typescript
const state = signalState({ ngrx: 'rocks' });
let changeCount = 0;
effect(() => {
changeCount++;
});
TestBed.flushEffects();
expect(changeCount).toBe(1);
patchState(state, {});
// before
expect(changeCount).toBe(2); // ✅
// after
expect(changeCount).toBe(2); // ❌ changeCount is still 1
```
## Further Changes
- `signalStoreFeature` had to be refactored because of typing issues with the change to `WritableStateSource`.
- `patchState` get the `NoInfer` for `updaters` argument. Otherwise, with multiple updaters, the former updater would have defined the `State` for the next updater.
52b0cba to
f39fa13
Compare
STATE_SOURCE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is a necessary refactoring to support a state which allows different types of Signals, i.e.
linkedSignal&signalbut still presents itself as a single unit to the outside.This commit splits the single Signal of
STATE_SOURCE, which contains the state in theSignalStoreandsignalState, into multiple Signals.An example. Given the following type:
Before,
STATE_SOURCEwould have been the following type:With this change, it is:
Most changes affect the tests which focus on the
STATE_SOURCE. Except for one test insignal-state.spec.ts('does not modify STATE_SOURCE'), all tests could be updated to assert the new behavior.Breaking Changes
STATE_SOURCEwill be impacted.different object reference for state of
STATE_SOURCESTATE_SOURCEdoes not keep the object reference of the initial state upon initialization.no Signal change on empty patched state
patchStatecreated a clone of the state and applied the patches to the clone. That meant, if nothing was changed, the Signal still fired because of the shallow clone. Since the state Signal doesn't exist anymore, there will be no change in this case.Further Changes
signalStoreFeaturehad to be refactored because of typing issues with the change toWritableStateSource.patchStateget theNoInferforupdatersargument. Otherwise, with multiple updaters, the former updater would have defined theStatefor the next updater.Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Does this PR introduce a breaking change?