In angular, if I have an effect which calls some method which further on sets some other signal, will that effect be bind to that "other signal" or just signals called directly inside the effect?
1 Answer
TLDR:
The effect tracks the signal reads present inside the effect and not all signals. If you do not want to specifically track certain signal reads, wrap then inside untracked.
... constructor() { effect(() => { console.log('in effect'); const triggerSignal = this.triggerSignal(); // changes are not tracked. const someOtherSignal = untracked(() => this.someOtherSignal()); ... Writing to a signal inside an effect but not reading it inside the effect
If you are reading the signal you are updating inside the effect, then the effect will trigger for ever update. If you are only writing to the signal and not reading it, the effect will not fire.
We need to keep in mind that only signals reads (this.triggerSignal()) are tracked inside the effect and not all the signals.
triggerSignal = signal(true); someOtherSignal = signal(''); constructor() { effect(() => { console.log('in effect'); const triggerSignal = this.triggerSignal(); if (triggerSignal) { this.updateSubSignal(); } }); } updateSubSignal() { // The below update does not retrigger the effect due to untracked. this.someOtherSignal.set('asdf'); } In the above code, effect is triggered only once. Since the signal being written (this.someOtherSignal.set('asdf')) is not read inside the effect.
Writing to a signal inside an effect but not reading it inside the effect - Stackblitz
Writing to a signal inside an effect and reading it inside the effect
In this scenario, the update of the signal ((this.someOtherSignal.set('asdf'))) triggers the effect again, because we are also reading the signal (this.someOtherSignal()) inside the effect.
triggerSignal = signal(true); someOtherSignal = signal('test'); constructor() { effect(() => { console.log('in effect'); const triggerSignal = this.triggerSignal(); const someOtherSignal = this.someOtherSignal(); if (triggerSignal && someOtherSignal) { this.updateSubSignal(); } }); } updateSubSignal() { // The below update does not retrigger the effect due to untracked. this.someOtherSignal.set('asdf'); } Note: This does not trigger an infinite loop, because signals updates are based on the actual value being changed (For primitives: number, string, etc) and memory reference updates (For non primitives: Array, Object, etc).
So the effect is triggered twice, once during initialization and again after update of the signal this.someOtherSignal.set('asdf') and the value change of someOtherSignal from 'test' to 'asdf', causes the effect to be triggered again.
Writing to a signal inside an effect and reading it inside the effect - Stackblitz
Writing to a signal inside an effect and reading it inside the effect but you do not want to track the updates:
For this specific purpose we have untracked:
Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function can, optionally, return a value.
Where even if you update a signal inside an effect, it will not retrigger the effect (because the updates are not tracked when you read using untracked callback).
triggerSignal = signal(true); someOtherSignal = signal('test'); constructor() { effect(() => { console.log('in effect'); const triggerSignal = this.triggerSignal(); const someOtherSignal = untracked(() => this.someOtherSignal()); if (triggerSignal && someOtherSignal) { this.updateSubSignal(); } }); } updateSubSignal() { // The below update does not retrigger the effect due to untracked. this.someOtherSignal.set('asdf'); } 3 Comments
if (this.disabled()), would later the change in the disabled cause effect to be called? Since this.disabled() is called nested inside updateSubSignal, and not directly in effect?someOtherSignal, it is will trigger the effect because someOtherSignal is used to calculate the computed signal that is read inside the effect.