Angular Signals — использование функции untracked() для предотвращения отслеживания зависимостей
Прежде чем читать эту статью, если вы не знакомы с Angular Signals, я бы рекомендовал вам прочитать мою предыдущую статью о сигналах Angular Signals.
Для каждого изменения сигнала 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");
// Устанавливаем сигнал для пользователей
untracked(() => this.users.set(1));
});
effect(() => {
// Будет вызван, когда сигнал пользователей будет установлен в предыдущем методе эффекта.
console.log("User effect invoked " + this.users());
});
}
}