State Management

NgRx и SignalStore (Angular)

Angular-команда строит личный кабинет банка. Корзина действий, история операций, статус загрузки выписки. Сначала всё держится в сервисах с BehaviorSubject, но через год потоки RxJS переплетаются так, что отладка занимает часы. Команда переходит на NgRx: каждое изменение это action, состояние пересобирает чистый reducer, побочные эффекты вынесены в effects. Через несколько лет Angular добавляет сигналы, и появляется SignalStore - тот же предсказуемый стор, но без церемоний RxJS вокруг простого чтения значения.

  • Крупные корпоративные SPA на Angular (банки, страховые, ERP), где аудит каждого изменения состояния важен
  • Дашборды с десятками панелей, где статус загрузки и кэш данных живут в едином сторе
  • Команды, мигрирующие со связки сервис плюс BehaviorSubject на NgRx ради предсказуемого потока
  • Новые Angular-проекты на SignalStore, где сигналы убирают часть boilerplate классического NgRx
  • Интеграция NgRx Effects с HTTP и WebSocket для серверных побочных эффектов

Предварительные знания

  • Идея однонаправленного потока Flux: action меняет состояние через reducer
  • Понимание чистой функции reducer: (state, action) даёт новое состояние без мутаций
  • Базовое представление о реактивности и подписке на поток значений
  • Flux и reducer

NgRx: Redux на Angular

NgRx переносит модель Redux в экосистему Angular. Состояние приложения хранится в едином store, изменения описываются через action, а новое состояние собирает чистая функция reducer. Поток строго однонаправленный: компонент диспатчит action, reducer пересчитывает состояние, подписчики получают обновление. Тот же Flux, что и в React-мире, но опирающийся на RxJS как на транспорт реактивности.

Action описывает намерение через строковый тип и опциональный payload. Reducer сопоставляет action с обработчиком через on и возвращает новое состояние без мутации старого. Структура повторяет Redux один в один, поэтому понимание Flux переносится сюда напрямую.

NgRx появился в 2016 году как порт Redux на Angular. Именно строгий поток и развитые devtools сделали его стандартом для крупных Angular-приложений, где важно отследить каждое изменение состояния по истории action.

Что в NgRx отвечает за пересчёт состояния в ответ на action?

Effects и selectors

Reducer обязан быть чистым, поэтому работе с сетью в нём не место. Эту задачу решают effects. Effect слушает поток action, выполняет побочный эффект (запрос к API, работа с WebSocket) и обычно диспатчит новый action с результатом. Так HTTP и асинхронность изолированы в отдельном слое на RxJS, а reducer остаётся предсказуемым.

Чтение состояния идёт через selectors. Selector это мемоизированная функция, которая выбирает срез store и пересчитывается только при изменении входных данных. Компонент подписывается на конкретный selector и обновляется лишь тогда, когда изменился именно его срез.

Селекторы можно собирать из других селекторов. selectIsPositive строится поверх selectCount и пересчитывается только при смене count. Это та же идея узкой подписки, что и селекторы в Zustand, но с встроенной мемоизацией.

Почему запрос к API выносят в effect, а не делают прямо в reducer?

SignalStore: стор на сигналах

С приходом сигналов в Angular NgRx выпустил SignalStore. Это стор, где состояние выражено сигналами, а не RxJS-потоками. Для чтения значения больше не нужен async-pipe или подписка: сигнал читается синхронно прямо в шаблоне. Boilerplate классического NgRx (отдельные файлы action, reducer, effects) сжимается до компактного описания стора.

Состояние описывается через withState, методы через withMethods, а patchState обновляет срез. Внутри компонента count читается как store.count() - обычный сигнал. Производные значения строятся через computed, побочные эффекты подключаются отдельным блоком. Модель ближе к Zustand: данные и методы в одном месте, без обширной обвязки.

  • Классический NgRx Store — Action, reducer, effects, selectors в отдельных слоях. Строгий аудит через историю action и развитые devtools. Уместен в крупных приложениях, где важна прослеживаемость каждого изменения
  • SignalStore — Состояние как сигналы, чтение без подписки и async-pipe, минимум boilerplate. Уместен в новых проектах на сигналах, где нужен предсказуемый стор без церемоний RxJS вокруг простого чтения

Оба подхода живут под зонтиком NgRx и могут сосуществовать. Полный разбор API, настройки и тестирования обоих сторов идёт в курсе по Angular - здесь дан обзор, чтобы видеть их место на карте state management.

Чем SignalStore отличается от классического NgRx Store при чтении состояния в шаблоне?

Связь с другими темами

Этот урок даёт обзор. Полный разбор Angular-инструментов идёт в профильном курсе:

  • NgRx Store, Effects и SignalStore в Angular — Реальный код, настройка стора, тестирование effects и миграция на сигналы разобраны в курсе по Angular
  • Flux и reducer — NgRx это прямое воплощение Flux на Angular: action, reducer и однонаправленный поток уже знакомы

Итог

  • NgRx переносит модель Redux в Angular: store, actions, reducers, selectors и effects для побочных эффектов
  • Reducer остаётся чистой функцией, effects изолируют работу с HTTP и WebSocket в отдельный слой на RxJS
  • Selectors дают мемоизированный доступ к срезам состояния, чтобы компоненты подписывались только на нужное
  • SignalStore это новый подход NgRx поверх Angular Signals: меньше boilerplate, чтение состояния как сигнала
  • Классический NgRx уместен в крупных приложениях с акцентом на аудит и devtools, SignalStore - в новых проектах на сигналах
  • Детали API, настройка и тестирование разбираются в курсе по Angular, здесь дан обзор для сравнения подходов

Связанные уроки

  • sm-07-flux-reducer — NgRx это Flux/Redux на Angular: те же action, reducer и однонаправленный поток, разобранные на уровне идеи в прошлом уроке
  • ng-39-ngrx-signalstore — Полный разбор NgRx Store, Effects и SignalStore с реальным кодом Angular живёт в курсе по Angular
NgRx и SignalStore (Angular)

0

1

Войти