惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
量子位
腾讯CDC
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
The Hacker News
The Hacker News
T
The Exploit Database - CXSecurity.com
B
Blog
S
SegmentFault 最新的问题
P
Privacy & Cybersecurity Law Blog
T
Threatpost
博客园 - 聂微东
T
Tailwind CSS Blog
The Last Watchdog
The Last Watchdog
C
Check Point Blog
N
Netflix TechBlog - Medium
D
DataBreaches.Net
爱范儿
爱范儿
IT之家
IT之家
S
Secure Thoughts
M
MIT News - Artificial intelligence
NISL@THU
NISL@THU
C
Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
有赞技术团队
有赞技术团队
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
Schneier on Security
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
雷峰网
雷峰网
Project Zero
Project Zero
博客园 - Franky
H
Heimdal Security Blog
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
State Management в Angular 19+: карта принятия решений
Евгений Козлов · 2026-06-26 · via Все публикации подряд на Хабре

На мою мою прошлую публикацию был дан всего один комментарий, но зато какой!

Отличный материал! Что бы быстро вникнуть в суть после легаси )

Чуваааак! Ты не представляешь до какой степени ты прав. Это действительно взгляд на ситуацию со стороны человека который 2 года провел на легасевом необитаемом острове и теперь обозревает окрестности.

А теперь детишки, мы продолжим наше знакомство с текущей ситуацией и на эту статью меня подвело исследование ситуации которая сложилась со State Management в Angular.

Достаточно долгое время выбор был достаточно простым:

  • ты решал не заплывать в бурное море и делал свой на базе RxJS + Services.

  • ты вздыхал и начинал грузить бойлерплейт бочками для NgRX.

  • ты брал NGXS и тоже грузил бойлерплейт, но не по самые шканцы и оставалось еще место чтоб втиснуть в каюту свое тщедушное тельце.

  • в приступе оптимизма ты ловил свежий ветер и шел к Akita.

Причем первые 2 варианта были в явных лидерах. Но прежде чем прежде чем скомандовать "По местам стоять, с якоря сниматься" посмотрим на карту и коротко пройдемся по всем вариантам. А потом взглянем на обновления.

Тихие воды Service + BehaviorSubject

interface User {
  name: string;
  lastName: string;
  isActive: boolean;
  existDate: Date;
}

@Injectable()
export class UserService {
  private http = inject(HttpClient);

  private _data = new BehaviorSubject<User[] | null>(null);

  get data$(): Observable<User[]>{
    return this._data
      .asObservable()
      .pipe(filter((user): user is User[] => user !== null));
  }
  get getActiveUsers$(){
    return this.data$.pipe(
      map((users: User[]) => users.filter(user => user.isActive))
    )
  }
  private set data$(data: User[]){
    this._data.next(data);
  }
  private addUser(user: User){
    const users: User[] = this._data.getValue() as User[];
    users?.push(user);
    this.data$ = users;
    this.addUserRequest(user);
  }

  loadUsers() {
    this.http.get<User[]>(`/api/users`)
      .subscribe(users => this.data$ = users);
  }
  addUserRequest(user: User){
    this.http.put<User>(`/api/users`, user)
      .subscribe(response => console.log(response))
  }
}

Достаточно стандартный подход начиная от ранних версий и до текущего момента. Все просто, понятно, прозрачно. Все под контролем и не нужно раздувать список зависимостей.

Из минусов: нужно помнить о необходимости отписок и некоторые промежуточные состояния трудно дебажить.

Еще существует утверждение что при разрастании такой вид стора начинает приобретать лапшеобразность. Утверждение все таки достаточно спорное. Большие сторы при отсутствии хорошего архитектора (а лучше всего чтоб он был еще президентом местного клуба самых нудных душнил) часто становятся трудно читаемыми и лапшеобразными вне зависимости от выбранной технологии. 

Не всякий клад стоит искать или почему не всегда нужен NgRx

NgRx задумывался как ответ на хаос. Redux паттерн, единый стор, неизменяемость, DevTools всё это реально помогало на больших проектах. Цена была высокой. Даже простое действие требовало:

action → reducer → effect (если асинхронный) → selector → компонент

ПЯТЬ ФАЙЛОВ для того чтобы правильно провести данные по одной сущности. Этого достаточно что бы джуниоры падали в обморок. Для всех проектов кроме большого и сложного энтерпрайза это был явный перебор.

Хватало случаев что в какой то команде приходили к решению на использование NgRX (или решение приходило сверху) в тех случаях где хватило бы Service + BehaviorSubject и потом лились кровавые слезы.

Отсюда по большей части и растут ноги репутации “NgRX - это очень сложно и много бойлерплейта”. Несмотря на то что бойлерплейта действительно много, сложность все таки значительно преувеличена. Комарадес это вы еще не ходили в React и не знакомились с такой вещью как Redux-Saga

Через рифы асинхронности. NGXS

Это тоже реализация паттерна Redux, тоже однонаправленный поток данных, единый источник истины. Но большое количество бойлерплейта упрятано под капот, меньше шаблонного кода по сравнению с NgRX. Прямо из коробки асинхронный подход, обработчики могут возвращать Observable или PromiseNGXS автоматически подпишется на них и будет ждать завершения, что упрощает работу с HTTP-запросами. Можно использовать привычный подход с setState, операторы состояния (state operators) для более декларативного обновления или даже интегрировать библиотеку для работы с иммутабельностью, например immer. Есть большой выбор плагинов. Например, плагин ngxs-requests-plugin упрощает управление состоянием HTTP-запросов (загрузка, ошибки)

Основные ключевые концепции те же:

  • Store : Глобальный иммутабельный объект,является единым источником истины для всего приложения.

  • State : Класс который управляет определенным срезом (slice) глобального состояния. Он скрывается под декоратором @State, ему присваивается уникальное имя и значение по умолчанию. 

  • Actions : Это простые методы класса которые описывают что должно произойти или уже произошло. Для обработки действия внутри класса состояния используется декоратор @Action. Метод-обработчик получает контекст StateContext, через который можно читать и изменять состояние.

@State<string[]>({
  name: 'animals',
  defaults: []
})
@Injectable()
export class AnimalsState {
  // Обработчик действия AddAnimal
  @Action(AddAnimal)
  addAnimal(ctx: StateContext<string[]>, action: AddAnimal) {
    // Получаем текущее состояние
    const state = ctx.getState();
    // Устанавливаем новое состояние
    ctx.setState([...state, action.animal]);
  }
}
  • Selectors: Функции которые прячутся за декоратором @Selector, и позволяют извлекать определенные части данных из Store.  Селекторы в NGXS могут быть мемоизированы, что повышает производительность, так как вычисления происходят только при изменении данных. Для упрощения их создания есть вспомогательные утилиты, например createPropertySelectors, которые автоматически генерируют селекторы для всех свойств состояния

@State<AnimalsStateModel>({ ... })
@Injectable()
export class AnimalsState {}

export class AnimalsSelectors {
  // Создает селекторы для zebras, pandas и monkeys
  static getSlices = createPropertySelectors<AnimalsStateModel>(AnimalsState);

  // Использование одного из них
  @Selector([AnimalsSelectors.getSlices.zebras])
  static getZebras(zebras: string[]) { return zebras; }
}
  • Actions Stream : Это RxJS Observable, через который проходят все отправленные действия. Вы можете подписаться на него, чтобы реагировать на жизненный цикл действий (ofActionSuccessful, ofActionErrored и т.д.), например, показывать уведомления после успешного выполнения операции.

В отличие от NgRx, который строго следует паттерну Redux с раздельными редьюсерами, эффектами и действиями, NGXS предлагает более простой и интуитивный подход, объединяя логику в классах состояния. Это делает NGXS хорошим выбором для среднего и крупного проекта, где важна скорость разработки, декларативный подход, но по каким то причинам не лежит душа к NgRx.

В целом, если вы ищете мощное, но более лаконичное решение для управления состоянием в Angular, NGXS отлично подойдет.

Корабль больших надежд. Akita

В свое время позиционировалась как еще более простая альтернатива NgRx 

Вот на чем строилась архитектура Akita:

  1. Store: Это класс, который содержит и управляет состоянием (state). Akita предлагает два основных типа хранилищ:

    • Store : для простого, неструктурированного состояния (например, настройки интерфейса) .

    • EntityStore : для управления коллекциями сущностей (например, список пользователей или задач). Это хранилище предоставляет встроенные методы для операций CRUD (addupdateremoveset), что очень удобно для работы со списками .

  2. Query: Классы, наследующие от Query или QueryEntity, которые служат для получения данных из хранилища в реактивном стиле через RxJS Observable. Они позволяют создавать селекторы для фильтрации, сортировки и комбинирования данных .

  3. Service: Это необязательный слой, который выступает в роли посредника. Компоненты вызывают методы сервиса, а тот, в свою очередь, выполняет бизнес-логику и обновляет хранилище. Такой подход помогает отделить логику обновления от компонентов.

Основная идея Akita заключалась в том чтоб предоставить разработчикам интуитивно понятный и гибкий API и сократить объем шаблонного кода по сравнению с более строгими реализациями Redux, (заявлялась что код можно сократить на 60%).EntityStore с готовыми методами для работы с сущностями и менее строгая архитектура обещали значительно упростить жизнь.

НО! Официальный репозиторий Akita на GitHub был заархивирован, а в документации указано, что библиотека больше не поддерживается . Разработчики рекомендуют перейти на новый проект Elf, который должен прийти на смену Akita .

А что с проектом Elf?

А Elf активно развивается и поддерживается. Она создана тем же автором, что и Akita, и если вам нравится то что было реализовано там, то лучше отдать предпочтения именно ему по ряду причин.

Это реактивное, иммутабельное хранилище состояний, построенное на RxJS. Его ключевая идея это простота и гибкость без лишнего шаблонного кода. Вместо монолитного подхода, Elf предлагает модульную архитектуру, где вы подключаете только необходимые функционал.

Для запроса данных используются RxJS-операторы, а для обновления чистые функции, что делает код предсказуемым и легко тестируемым.

Как и в Akita, в Elf есть первоклассная поддержка сущностей (withEntities), которая предоставляет удобные методы для CRUD-операций.

Библиотека предлагает широкий набор готовых решений (плагинов), которые подключаются по мере необходимости благодаря продуманной архитектуре:

  • Persist State: Позволяет легко сохранять состояние хранилища в localStorage или sessionStorage, чтобы восстанавливать его после перезагрузки страницы. Можно гибко настраивать, какие именно части состояния сохранять, исключать конфиденциальные данные и даже использовать асинхронные хранилища вроде IndexedDB.

  • Sync State: Обеспечивает синхронизацию состояния одного и того же хранилища между разными вкладками или окнами браузера с помощью Broadcast Channel API.

  • Другие плагины: Также доступны инструменты для работы с историей состояний, пагинацией, статусами запросов и интеграцией с Devtools.

По данным 2022 года, Elf был менее популярен, чем "гиганты" вроде NgRx (486k загрузок в неделю) или NGXS (118k), но уже имел свою аудиторию (~7.8k загрузок в неделю и 1k звезд на GitHub). Сейчас библиотека продолжает развиваться. Но!

Сокровище на десерт

Еще в июле 2024 года, когда библиотека вышла из стадии "developer preview", ее еженедельные загрузки уже достигли 50,000 . Это показывает невероятно быстрый старт.

А в 2026 году она и уверенно тянет ~793,000 - 857,000. Я сейчас говорю про NgRx Signal Store.

Ключевые концепции и API

Основой Signal Store является функция signalStore, которая действует как "конвейер", принимающий последовательность "фич" (features) для построения хранилища . Каждая фича добавляет определенную функциональность .

Вот основные строительные блоки (фичи), которые можно комбинировать для создания хранилища:

  1. withState: Добавляет срез состояния. Каждое свойство состояния автоматически становится вложенным сигналом (глубоким сигналом), что позволяет подписываться на изменения отдельных частей .

  2. withComputed: Добавляет вычисляемые сигналы, которые зависят от других сигналов в хранилище и автоматически обновляются при их изменении .

  3. withMethods: Добавляет методы для обновления состояния. Эти методы могут использовать утилиту patchState для частичного обновления, что делает код более читаемым по сравнению с ручным клонированием объектов .

  4. withHooks: Позволяет выполнять пользовательскую логику на этапах инициализации (onInit) и уничтожения (onDestroy) хранилища .

type Todo = { id: string; text: string; completed: boolean };
type TodoState = {
  items: Todo[];
  filter: 'all' | 'active' | 'completed';
  loading: boolean;
};

// Начальное состояние
const initialState: TodoState = {
  items: [],
  filter: 'all',
  loading: false
};

// Стор
export const TodoStore = signalStore(
  { providedIn: 'root' },
  
  // 1. Состояние
  withState(initialState),
  
  // 2. Вычисления
  withComputed(({ items, filter }) => ({
    filteredItems: computed(() => {
      const all = items();
      switch (filter()) {
        case 'active': return all.filter(t => !t.completed);
        case 'completed': return all.filter(t => t.completed);
        default: return all;
      }
    }),
    stats: computed(() => ({
      total: items().length,
      active: items().filter(t => !t.completed).length,
      completed: items().filter(t => t.completed).length
    }))
  })),
  
  // 3. Методы
  withMethods((store, http = inject(HttpClient)) => ({
    // Асинхронная загрузка
    load: rxMethod<void>(
      pipe(
        tap(() => patchState(store, { loading: true })),
        switchMap(() =>
          http.get<Todo[]>('/api/todos').pipe(
            tapResponse({
              next: (items) => patchState(store, { items, loading: false }),
              error: () => patchState(store, { loading: false })
            })
          )
        )
      )
    ),  
  // 4. Жизненный цикл
  withHooks({
    onInit({ load }) {
      load(); // Автозагрузка при создании
    }
  })
);

NgRx Signal Store  это современное, легковесное и официальное решение для управления состоянием в Angular, построенное на основе нативных Angular Signals . В отличие от классического NgRx Store с его действиями, редьюсерами и эффектами, Signal Store требует минимального шаблонного кода и предлагает интуитивно понятный API .

Помимо базовых фич, Signal Store предоставляет мощные инструменты для сложных сценариев:

  • withRxMethod: Для управления побочными эффектами и асинхронными операциями, такими как API-запросы, используется функция rxMethod . Она принимает цепочку RxJS-операторов и возвращает реактивный метод, который можно вызвать со значением, сигналом или Observable .

export const ProductsStore = signalStore(
  { providedIn: 'root' },
  withState(initialState),
  withMethods((store, productsService = inject(ProductsService)) => ({
    // Метод без параметров
    loadProducts: rxMethod<void>(
      pipe(
        // 1. Включаем индикатор загрузки
        tap(() => patchState(store, { isLoading: true })),
        // 2. switchMap отменит предыдущий запрос
        switchMap(() =>
          productsService.getProducts().pipe(
            tapResponse({
              // 3. Обработка успешного ответа
              next: (items) => patchState(store, { items, isLoading: false }),
              // 4. Обработка ошибки
              error: () => patchState(store, { isLoading: false })
            })
          )
        )
      )
    )
  }))
);
  • withEntities: Специализированный плагин для работы с коллекциями сущностей, который предоставляет готовые утилиты для CRUD-операций (addEntityupdateEntityremoveEntity и др.), что значительно упрощает управление списками .

// Вот и весь стор для хранения списка пользователей
export const UserStore = signalStore(
  { providedIn: 'root' },
  withEntities<User>() // <-- Добавляет все необходимое для управления сущностями
);

// а теперь используем его в компоненте
@Component({...})
export class UsersComponent {
  store = inject(UserStore);

  // Пример: загружаем список пользователей
  loadUsers(users: User[]) {
    // Используем хелпер setAllEntities для обновления всего списка
    patchState(this.store, setAllEntities(users));
  }

  // Пример: добавляем одного пользователя
  addUser(newUser: User) {
    patchState(this.store, addEntity(newUser)); // Используем хелпер addEntity
  }

  // Пример: обновляем пользователя
  updateUser(updatedUser: User) {
    // updateEntity обновляет сущность по ее ID
    patchState(this.store, updateEntity({ id: updatedUser.id, changes: updatedUser }));
  }

  // Пример: удаляем пользователя
  deleteUser(id: string) {
    patchState(this.store, removeEntity(id)); // removeEntity удаляет сущность по ID
  }

  // Получение всех сущностей (сигнал)
  get allUsers() {
    return this.store.entities(); // сигнал, содержащий массив всех пользователей
  }
}
  • signalStoreFeature: Позволяет создавать собственные переиспользуемые фичи, инкапсулируя в них общую логику, такую как состояние загрузки, интеграция с localStorage или отображение уведомлений. Это ключевой механизм для построения чистой и поддерживаемой архитектуры . Сообщество активно создает и делится такими фичами .

  • Инкапсуляция состояния: Начиная с версии 18, состояние хранилища по умолчанию защищено от внешних модификаций, что гарантирует предсказуемый поток данных. Это повышает надежность кода .

  • Приватные члены: Любой член хранилища (состояние, вычисляемый сигнал, метод), имя которого начинается с нижнего подчеркивания (_), считается приватным и недоступен извне. Это помогает четко разделять публичный API и внутреннюю реализацию .

  • watchState: Функция, позволяющая синхронно отслеживать все изменения состояния. Это полезно для реализации таких функций, как "отмена действий" (undo/redo) или ведение логов, где важна каждая промежуточная мутация, а не только финальное состояние 

NgRx Signal Store — это не просто альтернатива, а эволюция управления состоянием в Angular, тесно интегрированная с его современными реактивными примитивами. Судя по документации, активности сообщества и темпам развития, это официально рекомендуемый путь для создания новых приложений на Angular.

Итог: никакой войны, только инструменты

Сигналы не замена RxJS

Одна из главных ошибок последнего времени это пытаться переписать вообще всё на сигналы. Это неправильно. RxJS остаётся лучшим инструментом для работы со временем: debounce, throttle, отмена запросов, WebSocket-соединения.

И сейчас наиболее правильная картина организации выглядит так:

  • RxJS  для асинхронных потоков и управления временем

  • Signals  для хранения текущего состояния

Реальный профит по производительности

В одном из реальных проектов (22k строк TypeScript, маркетинговая аналитика) переход на сигналы дал:

  • Сокращение кода управления состоянием на 63% (8400 → 3100 строк)

  • Уменьшение бандла с 38 KB до 18 KB

  • Перерендеры при вводе: с 47 до 3 за одно нажатие клавиши

Миграция: не нужно переписывать всё сразу

Если у вас уже есть проект на NgRx не нужно бросать все силы на переписывание. Наилучшая стратегия:

  1. Новые фичи пишем на SignalStore или простых сигналах

  2. Старые фичи переписываем постепенно, когда они всё равно меняются

  3. Глобальное состояние (auth, permissions) оставляем на классическом NgRx или переводим на Service + Observable

Во время поиска информации мне попалась история одной миграции. В одном из реальных проектов во время миграции существовало три вида стейтов: NgRx + сигналы + один legacy-компонент на Akita. И это нормально.

В 2026 году Angular даёт разработчикам набор инструментов, а не догму. Сигналы не убили NgRx но необходимости его использовать стало еще меньше. RxJS не умер он занял своё законное место на границе с асинхронностью.

Главный принцип: состояние это не одна библиотека на всё приложение. Это выбор правильного инструмента под конкретную задачу. Для локального UI сигналы. Для серверного кэша TanStack Query или toSignal. Для сложных асинхронных сценариев RxJS + Signals. Для глобального состояния с аудитом NgRx Classic или SignalStore , или Elf если нравиться подход RxJS.

И самое важное: не нужно переписывать всё с нуля. Мигрируйте постепенно, фича за фичей. Берегите себя и свою команду.