Зависимое состояние с linkedSignal
Вы можете использовать функцию signal, чтобы хранить некоторое состояние в коде Angular. Иногда это состояние зависит от какого-либо другого состояния. Например, представьте компонент, который позволяет пользователю выбрать способ доставки заказа:
@Component({
/* ... */
})
export class ShippingMethodPicker {
shippingOptions: Signal<ShippingMethod[]> = getShippingOptions();
// Select the first shipping option by default.
selectedOption = signal(this.shippingOptions()[0]);
changeShipping(newOptionIndex: number) {
this.selectedOption.set(this.shippingOptions()[newOptionIndex]);
}
}
В этом примере selectedOption по умолчанию соответствует первому варианту, но меняется, если пользователь выбирает другой вариант. Однако shippingOptions — это сигнал, его значение может измениться! Если shippingOptions изменится, selectedOption может содержать значение, которое больше не является допустимым вариантом.
Функция linkedSignal позволяет создать сигнал для хранения состояния, которое неразрывно связано с другим состоянием. Вернёмся к примеру выше: linkedSignal может заменить signal:
@Component({
/* ... */
})
export class ShippingMethodPicker {
shippingOptions: Signal<ShippingMethod[]> = getShippingOptions();
// Initialize selectedOption to the first shipping option.
selectedOption = linkedSignal(() => this.shippingOptions()[0]);
changeShipping(index: number) {
this.selectedOption.set(this.shippingOptions()[index]);
}
}
linkedSignal работает подобно signal, но с одним важным отличием: вместо передачи значения по умолчанию вы передаёте функцию вычисления, как и в случае с computed. Когда результат вычисления меняется, значение linkedSignal становится равным результату вычисления. Это помогает гарантировать, что linkedSignal всегда содержит допустимое значение.
В следующем примере показано, как значение linkedSignal может меняться в зависимости от связанного с ним состояния:
const shippingOptions = signal(['Ground', 'Air', 'Sea']); const selectedOption = linkedSignal(() => shippingOptions()[0]); console.log(selectedOption()); // 'Ground' selectedOption.set(shippingOptions()[2]); console.log(selectedOption()); // 'Sea' shippingOptions.set(['Email', 'Will Call', 'Postal service']); console.log(selectedOption()); // 'Email'
Учёт предыдущего состояния
В некоторых случаях при вычислении значения linkedSignal необходимо учитывать предыдущее значение linkedSignal.
В примере выше selectedOption всегда возвращается к первому варианту, когда меняется shippingOptions. Однако может потребоваться сохранить выбор пользователя, если выбранный им вариант всё ещё есть в списке. Для этого можно создать linkedSignal с отдельными параметрами источника и вычисления:
interface ShippingMethod {
id: number;
name: string;
}
@Component({
/* ... */
})
export class ShippingMethodPicker {
constructor() {
this.changeShipping(2);
this.changeShippingOptions();
console.log(this.selectedOption()); // {"id":2,"name":"Postal Service"}
}
shippingOptions = signal<ShippingMethod[]>([
{id: 0, name: 'Ground'},
{id: 1, name: 'Air'},
{id: 2, name: 'Sea'},
]);
selectedOption = linkedSignal<ShippingMethod[], ShippingMethod>({
// `selectedOption` is set to the `computation` result whenever this `source` changes.
source: this.shippingOptions,
computation: (newOptions, previous) => {
// If the newOptions contain the previously selected option, preserve that selection.
// Otherwise, default to the first option.
return newOptions.find((opt) => opt.id === previous?.value.id) ?? newOptions[0];
},
});
changeShipping(index: number) {
this.selectedOption.set(this.shippingOptions()[index]);
}
changeShippingOptions() {
this.shippingOptions.set([
{id: 0, name: 'Email'},
{id: 1, name: 'Sea'},
{id: 2, name: 'Postal Service'},
]);
}
}
При создании linkedSignal можно передать объект с отдельными свойствами source и computation вместо того, чтобы указывать только вычисление.
В качестве source может выступать любой сигнал, например computed или компонентный input. Значение linkedSignal обновляется при изменении source или любого сигнала, на который ссылается computation; новое значение определяется результатом переданного computation.
computation — это функция, которая получает новое значение source и объект previous. У объекта previous есть два свойства: previous.source — предыдущее значение source, а previous.value — предыдущее значение linkedSignal. Эти предыдущие значения можно использовать, чтобы определить новый результат вычисления.
ПОЛЕЗНО: При использовании параметра previous необходимо явно указывать аргументы обобщённого типа для linkedSignal. Первый аргумент обобщённого типа соответствует типу source, а второй определяет выходной тип computation.
Пользовательское сравнение на равенство
Для linkedSignal, как и для любого другого сигнала, можно настроить пользовательскую функцию сравнения на равенство. Зависимые от него сигналы используют эту функцию, чтобы определить, изменилось ли значение linkedSignal (результат вычисления):
const activeUser = signal({id: 123, name: 'Morgan', isAdmin: true});
const activeUserEditCopy = linkedSignal(() => activeUser(), {
// Consider the user as the same if it's the same `id`.
equal: (a, b) => a.id === b.id,
});
// Or, if separating `source` and `computation`
const activeUserEditCopy = linkedSignal({
source: activeUser,
computation: (user) => user,
equal: (a, b) => a.id === b.id,
});
Super-powered by Google ©2010–2025.
Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
https://angular.dev/guide/signals/linked-signal