Хранилища сигналов в сервисах
Храните состояние приложения в сервисах на основе сигналов
«Хранилища сигналов в сервисах» — бесплатный урок Angular Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Angular Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Angular Academy содержит 4 уроков всего.
Сигналы как состояние
Сигналы Angular — это реактивные значения, которые уведомляют потребителей об изменениях. Сигнал хранит значение и повторно запускает любое вычисление или шаблон, который его читает.
Хранение сигналов внутри сервиса @Injectable позволяет нескольким компонентам использовать одно и то же реактивное состояние.
Минимальное хранилище сигналов
Создайте сервис и храните состояние в signal(). Оставьте изменяемый сигнал приватным, а наружу откройте доступное только для чтения представление.
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class CounterStore {
private _count = signal(0);
readonly count = this._count.asReadonly();
increment() { this._count.update(c => c + 1); }
}Почему providedIn root
providedIn: 'root' делает сервис единственным экземпляром во всём приложении. Каждый компонент, который внедряет его, использует один и тот же экземпляр сигнала, поэтому состояние остаётся синхронизированным.
Чтение сигнала
Вызовите сигнал как функцию, чтобы прочитать его значение. В шаблоне Angular отслеживает такое чтение и автоматически обновляет DOM при изменении значения.
import { Component, inject } from '@angular/core';
import { CounterStore } from './counter.store';
@Component({
selector: 'app-counter',
template: '<button (click)="store.increment()">{{ store.count() }}</button>'
})
export class CounterComponent {
store = inject(CounterStore);
}asReadonly защищает состояние
asReadonly() возвращает сигнал, который можно читать, но нельзя изменять. Компоненты не смогут случайно вызвать для него set() или update(), поэтому все изменения проходят через методы хранилища.
set и update
Используйте set(value), когда следующее значение уже известно. Используйте update(fn), когда следующее значение зависит от текущего.
private _user = signal<User | null>(null);
setUser(u: User) { this._user.set(u); }
clearUser() { this._user.set(null); }
touch() { this._user.update(u => u ? { ...u, seen: true } : u); }Несколько сигналов в одном хранилище
Хранилище может содержать несколько сигналов, представляющих разные части состояния. Оставляйте каждый изменяемый сигнал приватным и открывайте соответствующие представления только для чтения.
private _items = signal<Item[]>([]);
private _loading = signal(false);
readonly items = this._items.asReadonly();
readonly loading = this._loading.asReadonly();Методы инкапсулируют логику
Бизнес-правила должны находиться в методах хранилища, а не в компонентах. Компоненты вызывают методы, явно выражающие намерение, например addToCart(item), а хранилище решает, как изменить состояние.
addToCart(item: Item) {
this._items.update(list => [...list, item]);
}
removeFromCart(id: string) {
this._items.update(list => list.filter(i => i.id !== id));
}Подписки не нужны
В отличие от сервисов на основе RxJS, хранилищам сигналов не нужны subscribe() и ручная отмена подписок. Чтение сигнала в шаблоне настраивает реактивность, а Angular очищает её при уничтожении компонента.
Внедрение с помощью inject()
Функция inject() работает в конструкторах, инициализаторах полей и фабричных функциях. Это современный способ получить экземпляр хранилища.
export class CartComponent {
private store = inject(CartStore);
items = this.store.items; // read-only signal
}Тестирование хранилища сигналов
Хранилища сигналов — это обычные классы, поэтому тесты просты: создайте экземпляр, вызовите метод и синхронно прочитайте значение сигнала. Дополнительная асинхронная инфраструктура не требуется.
it('increments', () => {
const store = new CounterStore();
store.increment();
expect(store.count()).toBe(1);
});Быстрая проверка
Проверьте, насколько хорошо Вы понимаете хранилища сигналов.
Итоги
Вы научились создавать хранилище на основе сигналов: оставлять изменяемые сигналы приватными, открывать представления asReadonly(), изменять состояние через set/update внутри методов и внедрять единственный экземпляр с помощью inject(). Подписки не нужны, тестирование просто, реактивное состояние общее.
Часто задаваемые вопросы
Урок «Хранилища сигналов в сервисах» бесплатный?
Да — полный текст урока «Хранилища сигналов в сервисах» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Angular Academy, подпишись на CoddyKit PRO. Курс Angular Academy содержит 4 уроков всего.
Чему я научусь в уроке «Хранилища сигналов в сервисах»?
Храните состояние приложения в сервисах на основе сигналов Ты практикуешь Angular Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Angular Academy?
Предыдущий опыт не требуется. Angular Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Хранилища сигналов в сервисах»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Angular Academy?
Да. Каждый урок Angular Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Хранилища сигналов в сервисах
- Выведение состояния с помощью computed
- Иммутабельное обновление состояния
- Связывание сигналов и RxJS