stephan.peters
stephan.peters

Reputation: 1107

Changing external shared service signal in an effect

I have a shared service with signals for everything regarding layout. This is in an external library.

In a component within an application I want to set a signal in this shared service. The problem is that you need to set allowSignalWrites to true in this case on the effect.

The official documentation from Angular also explains that the untracked function can be used to call external code.

Would this be a good alternative to setting allowSignalWrites to true? Because the comment on that property doesn't encourage the use of it.

// signal in the application (invoice detail page)
readonly #invoice = this.#localStore.invoice;
// shared service for the layout (note that the layout is shared accross pages)
readonly #layout = inject(SharedLayoutService); 

effect(() => {
   if (this.#invoice()) {
      const subtitle = `Invoice${this.#invoice().reference}`;
      untracked(() => this.#layout.subTitle.set(subtitle); });
    });
 });

Upvotes: 1

Views: 455

Answers (1)

user680786
user680786

Reputation:

effect() is a consumer of every signal it reads.

Signals (producers) notify their consumers about every change. After that, consumers will re-read the values of producers (eventually).

To read values, effect() runs the function you passed as the first argument.

It means, that effect() will execute that function every time the related signals are modified.

If you modify involved signals inside the function you passed to effect(), it will cause an endless loop. Some signals are derived (computed()), so you might modify signals you read indirectly:

a = signal(0);
b = signal(0);
c = computed(() => a() + b());

constructor() {
   effect(() => {
     if (this.c() > 1) {
       this.a.update(a => a * 2); // endless loop, because c is changed
     }
  });
}

It is just one of the reasons why documentation says that you should avoid effect().

Now we can see the difference between allowSignalWrites and untracked():

  • By setting allowSignalWrites you are saying "I know what I'm doing, no bad things will happen, and I want my effect to keep listening to every signal it reads - they will not be modified in this effect".
  • By using untracked() you are saying "I can not be sure that it will not cause indirect modifications of the signals this effect reads, so please do not listen to the changes it might cause (do not track them)".

As you can see, untracked() is more safe to use, allowSignalWrites is only for the cases when you can clearly see that no indirect changes will happen.

But even with untracked() you should be sure that by modifying this signal you will not trigger ExpressionChangedAfterItHasBeenChecked (yes, it is possible).

Upvotes: 2

Related Questions