#Signals called from a property and property used on a template: still reactive?

40 messages · Page 1 of 1 (latest)

untold mango
#

So I have a situation where some code is written where it is being called in a getter such as:

get someValue() { 
  return this.someSignal();
}

And someValue is used in a template perhaps {{ someValue }}

Does this still react as if you had called someSignal() straight in the template?

I would not have written code like this but the technical question was brought up if it is any different.

fluid horizon
#

If this.someValue is called in template or effect. Then it is still reactive. Needs untracked somewhere to prevent leak.

untold mango
#

Can you describe what you mean by leak in this case?

fluid horizon
#

Instead of {{ someSignal() }}, you wrote {{ someValue }}, I guessing you trying to contain the reactivity

untold mango
#

Oh I don't think there was any thought by the person writing this to that.

#

Is there any technical reason why this should not be done?

fluid horizon
#

In that case, {{ someSignal() }} and {{ someValue }} has no different in this case

#

No no, nothing about this can't be done.

#

{{ someSignal() }} and {{ someValue }} has no difference in this case.

untold mango
mint linden
#

No, as far as change detection, etc. is concerned {{ someSignal() }} and {{ someGetterThatCallsASignal }} should behave identically

#

You are probably referring to this comment:

It doesn't cause any errors, but as I mentioned above, it is called on every cycle no matter if signal inside a getter was changed.
This is true, however this is also true for the signal. someSignal() will be evaluated on every CD cycle for the component

#

This is why you still should use OnPush even when using signals

untold mango
#

I am working on getting more OnPush in this project :-).

#

Does this track signals essentially the same way in the template as an effect/computed might?

mint linden
#

In fact it is exactly the same mechanism under the hood, yes.

untold mango
#

In 19 (we haven't upgraded yet), do these provide more surgical updates of the templates?

mint linden
#

No and they don't in 20 either and neither in 21 (from what I know)

#

When a signal you read in your component changes, it basically does a ChangeDetectorRef#markForCheck as far as I understand it

#

Of course Angular won't needlessly update the DOM, but it still checks your whole template, not just parts of it.

#

If you then use OnPush everywhere that means that only those componets where something actually changed run change detection, but those templates are still checked as a whole.

untold mango
#

If I remember correctly, OnPush specifically checks inputs, but also observables through |async and signals - how do observables and signals notify of changes?

mint linden
#

OnPush has nothing to do with async or signals.
OnPush says to only check a component if its inputs change. Opposed to that is default change detection, where components will always be checked on every cycle.

The async pipe tells Angular to run change detection on the component where it is used explicitly when its observable emits a new value. This is independent of the change detection mode, but it will also work in OnPush mode. Same for signals, they also explicitly mark the component for change detection. This also works in both modes.

The difference is that with OnPush your component won't also be checked if something happens elsewhere in your app.

untold mango
#

Thank you for these details, it is very helpful.

untold mango
mint linden
#

Probably because events often cause things to happen in parent components as well. Imagine (in that example) LoginComponent emits a "submit" output when a click event happens inside it and as a result MainComponent changes its state. If only LoginComponent were checked then MainComponent's view would not update

#

You have to keep in mind that these rules were made before signals. So the following needs to work:

<app-login (login)="doLogin()" />
class MainComponent {
  loading = false;

  doLogin() { 
    this.loading = true;
    // do stuff
  }
}
rancid smelt
#

the wording in the doc seems a bit imprecise

stuff under AppComponent that isn't also OnPush: because it isn't OnPush, and "something" changed.

ancestor that is OnPush: guessing because the children --heh this part was answered

sibling that isn't OnPush: because it isn't OnPush

untold mango
#

@mint linden it sounds like sometime in the future there may be a need for another change detection mode that doesn't include this functionality, if it is in fact costly. Zoneless might come up in events.

mint linden
#

Zoneless is - again - orthogonal to most of this. Zoneless basically means that Angular does not instrument pretty much every async api (setTimeout, RxJS, promises and many more). Zone.js patches all of these and whenever "something happens there" (e.g. a setTimeout runs or a promise resolves) Zone tells Angular to run change detection.
With Zoneless this does not happen and Angular will only run change detection through more "normal" means, i.e. an input changed, an event happend, a signal read by a template changed (or you just tell it to via ChangeDetectorRef).
This does not change what is checked (that's what OnPush is for).

As for "another change detection mode" - sure, that could be possible. However if you write OnPush everywhere and use signals my guess is you would not see many performance gains. Reading signals is dirt cheap and so checking a view which reads a few signals is super fast.

fluid horizon
#

This may be another example why ancestor has to be checked.

@Component({
template: `
 <childA #a />
 <p>{{ a.value }}</p>
`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent

a.value is even not a signal but will update correctly (BUT the changes of a.value has to be synchronous, and caused by a user-interaction, click, keydown etc)

quartz grove
#

With OnPush + signals you actually get some "local" CD

#

Basically when a signal marks a component dirty, if the component is OnPush the parents aren't checked.

#

This doesn't include the case where an event listener is fired.

#

An event listener will mark all parent component as dirty, thus they'll be checked even if is no signals or input changed

mint linden
#

Oh nice

mint bane
#

I think I saw a PR experimenting with a CD strategy where event listeners would not caus change detection (which looks normal to me, given that if the listener makes a change, it should do so by updating a signal).
Will that be integrated at some point?

quartz grove
#

It has been investigated