Прежде чем читать эту статью, если вы не знакомы с сигналами Angular, я бы рекомендовал прочитать мой предыдущий пост о сигналах — Сигналы Angular🚦: Новая стратегия обнаружения изменений.

При каждом изменении сигнала функции computed и effect, которые заинтересованы в сигнале, будут пересчитываться и выполняться соответственно. Бывают случаи, когда мы не хотим, чтобы этот повторный расчет происходил при изменении сигнала. В сигналах Angular все зависимости будут выполняться внутри реактивного контекста. Чтобы избежать повторных вычислений, их следует запускать внутри нереактивного контекста.

Angular предоставил функцию untracked, которая позволяет выполнять любую функцию в нереактивном контексте и иногда возвращает значения.

Давайте рассмотрим некоторые варианты использования неотслеживаемой функции.

Вычислите вычисленное свойство сигнала только один раз

В некоторых случаях вам может понадобиться вычисляемый сигнал, который будет вычислять свое значение только один раз и не будет учитывать дальнейшие изменения. В таких случаях вы можете использовать функцию untracked внутри вычисляемого сигнала для чтения значения сигнала без отслеживания зависимостей.

export class AppComponent {
  
  count = signal(1);
  
  revenue = computed(() => untracked(() => this.count() * 5));
}

В приведенном выше коде вычисляемый сигнал revenue будет вычисляться только один раз (значение будет равно 5) на основе его зависимости count. При последующих операциях с набором выручка не будет пересчитываться и останется в том же значении.

Чтение без отслеживания зависимостей в методе эффекта

Это очень распространенное использование, на которое указала команда angular. Вы можете использовать этот метод для неотслеживаемого чтения значений сигнала внутри метода effect, чтобы при дальнейшем изменении сигнала effect не вызывался.

export class AppComponent {
  
  count = signal(1);
  
  revenue = computed(() => untracked(() => this.count() * 5));

  constructor() {
    effect(() => {
      console.log('Count effect invoked ' + untracked(this.count));
    });
  }

}

Развернуть значение сигнала

Что ж, это очень простой вариант использования, он, вероятно, вам не понадобится, но я думаю, что об этом стоит упомянуть. Функция untracked вернет значение, которое мы можем использовать. Вы можете использовать эту функцию, чтобы просто развернуть или выполнить любую произвольную функцию.

В приведенном ниже коде nCount просто разворачивает значение сигнала, а factor будет хранить результат выполнения произвольной функции внутри неотслеживаемой функции.

export class AppComponent {
 
  count = signal(1);
  users = signal(0);
  nCount = untracked(this.count)
  factor = untracked(() => { 
              const count = this.count();
              const users = this.users() || 5;
              return count / users;
            });
  
  revenue = computed(() => untracked(() => this.count() * 5));

  constructor() {
    effect(() => {
      console.log('Count effect invoked ' + untracked(this.count));
    });
  }

}

Можно ли установить/обновить/изменить любое значение сигнала без уведомления зависимостей, используя неотслеживаемую функцию?

Ответ – большое НЕТ.

Установка или изменение значений сигналов внутри неотслеживаемой функции не помешает ей отслеживать и уведомлять о зависимостях.

Установка значения сигнала внутри неотслеживаемой функции позволит отслеживать зависимости и уведомлять заинтересованных потребителей.

В приведенном ниже коде установка сигнала users внутри неотслеживаемой функции не помешает ей уведомлять потребителей, и будет вызвана функция effect, использующая функцию users.

export class AppComponent {

  toggle = signal(true);
  count = signal(1);
  users = signal(0);
  nCount = untracked(this.count)
  factor = untracked(() => { 
              const count = this.count();
              const users = this.users() || 5;

              return count / users;
            });
  
  revenue = computed(() => untracked(() => this.count() * 5));

  constructor() {
    effect(() => {
      console.log('Empty effect method');
      // SETTING THE users signal 
      untracked(() => this.users.set(1));
    });

    effect(() => {
      // Will be called when 
      // users signal is set in the previous effect method.
      console.log('User effect invoked ' + this.users());
    });
  }

}

Надеюсь, вам понравится читать эту статью. Если вы считаете это полезным, подпишитесь на меня на Medium или в Твиттере, чтобы не пропустить подобный контент.

Приятного кодирования…

Спасибо, что дочитали до конца. Пожалуйста, подумайте о том, чтобы подписаться на автора и эту публикацию. Посетите Stackademic, чтобы узнать больше о том, как мы демократизируем бесплатное образование в области программирования во всем мире.