Reputation: 1
While moving into the world of signals our team have encountered seemingly odd issue. Let's imagine a component with effect on signal which is a public member there. In component constructor some logic is performed which updates signal value multiple times. The expectation was, this will be reflected by firing effect same amount of times that signal value updates were performed, but it actually does not happen in such way. Instead effect is fired first time after whole component initialization is over.
Let's look at example I have prepared on StackBlitz DEMO
constructor() {
effect(() => {
this.effectLogs.push(JSON.stringify(this.valueSignal()));
if (this.valueSignal().length == 1 || this.valueSignal().length == 2) {
alert('Im never triggered');
}
});
this.insertFirstValue();
// possibly some other logic here
this.valueSignal.update((val) => [...val, 'constructor-1']);
setTimeout(() =>
this.valueSignal.update((val) => [...val, 'constructor-2'])
);
}
ngOnInit() {
this.valueSignal.update((val) => [...val, 'init-3']);
}
private insertFirstValue() {
this.valueSignal.update((val) => [...val, 'constructor-0']);
}
The result of this effect setting up logs look like following:
["constructor-0","constructor-1","init-3"]
["constructor-0","constructor-1","init-3","constructor-2"]
As first effect result was pushing already 3 values the conditional alert defined in effect does never fire away. In our situation this is a bit more complex, since we based store feeding on some signal value conditions, which behave in same 'incorrect' way.
We started from extracting the problematic part, hoping it's something in our implementation. DEMO proves it's some general behavior. Maybe it's some misconception on how this should resolve in runtime, but I have not found actual piece of documentation addressing this issue, similarly to Stack Overflow. In example i played a bit, added button to add new entry twice, tried to utilize computed, added timeout, and all those things seemed helpless (except timeout).
Upvotes: 0
Views: 2879
Reputation: 55544
Signal are a bit different from the Observable when emitting update notifications.
The basic idea is the Signals are glitch-free, there are separate update / notifcation phases.
This means, when reading signals you know they all have been updates.
The consequence of this is that not every signal update will trigger an effect. The keyword to keep in mind is "eventually".
Signals eventualy emit a notifcation that they have been updated.
This is visible in your case when logging the size of the array:
> 4
> 5
the basic repro to illustrate this is
const mySignal() = signal(1);
effect(() => console.log(mySignal());
mySignal.set(2);
mySignal.set(3);
mySignal.set(4);
If you test this, you'll see that only 4
will be logged.
Upvotes: 2