NgRx Signal Store vs NgRx Clássico em 2026: Qual Escolher?
Comparação detalhada entre NgRx Signal Store e NgRx clássico para gerenciamento de estado Angular. Aprenda quando usar cada abordagem com exemplos de código práticos.

NgRx Signal Store representa uma mudança fundamental no gerenciamento de estado do Angular, substituindo o padrão tradicional inspirado no Redux (actions-reducers-selectors) por uma abordagem reativa baseada em signals. Com NgRx 22 (publicado em agosto de 2026), Signal Store ganha extensões de resource, signals profundos dinâmicos e melhor composabilidade. Esta comparação examina ambas as soluções para ajudar desenvolvedores Angular a tomar decisões arquiteturais informadas.
Usar Signal Store para estado em nível de funcionalidade, aplicações de complexidade média e integração nativa com a API Resource do Angular. Usar NgRx Clássico para aplicações empresariais que requerem trilhas de auditoria rigorosas, efeitos colaterais complexos e depuração extensiva com DevTools.
Entendendo as Diferenças Arquiteturais
NgRx clássico segue o padrão Redux: as actions descrevem eventos, os reducers produzem novo estado imutável, e os selectors extraem dados. Cada mudança de estado flui através de um pipeline previsível e rastreável.
Signal Store adota uma abordagem diferente. Em vez de despachar actions através de reducers, o estado vive em signals reativos. As atualizações acontecem através de métodos que chamam patchState(), e os valores derivados vêm de signals computados em vez de selectors memorizados.
| Aspecto | NgRx Clássico | Signal Store |
|---|---|---|
| Modelo Mental | Redux/Flux | Serviços Reativos |
| Boilerplate | Alto (actions, reducers, selectors, effects) | Baixo (state, methods, computed) |
| Reatividade | Observables RxJS | Signals Angular |
| API Resource | Integração manual | Nativa com @ngrx/signals/resource |
| DevTools | Redux DevTools completo | Signal Store DevTools (via plugin) |
| Curva de aprendizado | Íngreme | Moderada |
| Tamanho do Bundle | Maior (~15-20KB gzipped) | Menor (~4KB gzipped) |
Para desenvolvedores já familiarizados com Signals do Angular, Signal Store parece uma extensão natural das primitivas reativas do framework.
NgRx Clássico: O Padrão Redux no Angular
NgRx clássico organiza o gerenciamento de estado em torno de actions, reducers, selectors e effects. Essa separação impõe previsibilidade ao custo de verbosidade.
import { createActionGroup, emptyProps, props } from '@ngrx/store';
import { Book } from './book.model';
export const BooksActions = createActionGroup({
source: 'Books',
events: {
'Load Books': emptyProps(),
'Load Books Success': props<{ books: Book[] }>(),
'Load Books Failure': props<{ error: string }>(),
'Add Book': props<{ book: Book }>(),
'Remove Book': props<{ id: string }>(),
},
});A API createActionGroup agrupa actions relacionadas sob uma única fonte, melhorando a legibilidade no DevTools e reduzindo o boilerplate comparado com chamadas individuais de createAction.
import { createReducer, on } from '@ngrx/store';
import { BooksActions } from './books.actions';
import { Book } from './book.model';
export interface BooksState {
books: Book[];
loading: boolean;
error: string | null;
}
const initialState: BooksState = {
books: [],
loading: false,
error: null,
};
export const booksReducer = createReducer(
initialState,
on(BooksActions.loadBooks, (state) => ({
...state,
loading: true,
error: null,
})),
on(BooksActions.loadBooksSuccess, (state, { books }) => ({
...state,
books,
loading: false,
})),
on(BooksActions.loadBooksFailure, (state, { error }) => ({
...state,
loading: false,
error,
}))
);Os reducers continuam sendo funções puras que retornam novos objetos de estado. A função on() lida com a correspondência de actions e atualizações de estado de forma concisa.
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { BooksState } from './books.reducer';
export const selectBooksState = createFeatureSelector<BooksState>('books');
export const selectAllBooks = createSelector(
selectBooksState,
(state) => state.books
);
export const selectBooksLoading = createSelector(
selectBooksState,
(state) => state.loading
);
export const selectPublishedBooks = createSelector(
selectAllBooks,
(books) => books.filter((book) => book.published)
);Os selectors fornecem memorização automaticamente. O selector selectPublishedBooks só recalcula quando o array de livros muda, tornando as leituras eficientes mesmo em stores atualizados frequentemente.
NgRx Signal Store: Gerenciamento de Estado Signals-First
Signal Store consolida estado, valores computados e métodos em um único serviço injetável. A documentação oficial do NgRx o descreve como uma "solução de gerenciamento de estado completamente equipada com suporte nativo para Signals do Angular."
import { computed, inject } from '@angular/core';
import { patchState, signalStore, withComputed, withMethods, withState } from '@ngrx/signals';
import { BooksService } from './books.service';
import { Book } from './book.model';
interface BooksState {
books: Book[];
loading: boolean;
error: string | null;
}
const initialState: BooksState = {
books: [],
loading: false,
error: null,
};
export const BooksStore = signalStore(
{ providedIn: 'root' },
withState(initialState),
withComputed(({ books }) => ({
publishedBooks: computed(() => books().filter((book) => book.published)),
totalBooks: computed(() => books().length),
})),
withMethods((store, booksService = inject(BooksService)) => ({
async loadBooks() {
patchState(store, { loading: true, error: null });
try {
const books = await booksService.getAll();
patchState(store, { books, loading: false });
} catch (error) {
patchState(store, { loading: false, error: 'Failed to load books' });
}
},
addBook(book: Book) {
patchState(store, ({ books }) => ({ books: [...books, book] }));
},
removeBook(id: string) {
patchState(store, ({ books }) => ({
books: books.filter((book) => book.id !== id),
}));
},
}))
);Todo o gerenciamento de estado de uma funcionalidade cabe em um único arquivo. As propriedades de estado se tornam signals automaticamente, signals computados substituem selectors, e métodos substituem despachos de actions.
NgRx 22: Extensões de Resource e withProps
NgRx 22 introduz o ponto de entrada @ngrx/signals/resource, habilitando integração direta com a API Resource do Angular. A funcionalidade withProps centraliza a injeção de serviços, enquanto as extensões de resource lidam com padrões assíncronos comuns.
import { computed, inject } from '@angular/core';
import { patchState, signalStore, withComputed, withMethods, withProps } from '@ngrx/signals';
import { extendResource, withPreviousValueOnLoading, withValueOnError } from '@ngrx/signals/resource';
import { httpResource } from '@angular/core';
import { BooksService } from './books.service';
import { Book } from './book.model';
export const BooksResourceStore = signalStore(
{ providedIn: 'root' },
// Injeção de serviços via withProps (privado por convenção com underscore)
withProps(() => ({
_booksService: inject(BooksService),
})),
// Configuração de resources com extensões
withProps((store) => ({
_booksResource: extendResource(
httpResource<Book[]>({
url: '/api/books',
defaultValue: [],
}),
withPreviousValueOnLoading(), // Mantém o último valor durante o recarregamento
withValueOnError([]) // Retorna array vazio em caso de erro
),
})),
// Exposição somente leitura para os consumidores
withProps((store) => ({
booksResource: store._booksResource.asReadonly(),
})),
withComputed((store) => ({
books: computed(() => store.booksResource.value()),
isLoading: computed(() => store.booksResource.isLoading()),
publishedBooks: computed(() =>
store.booksResource.value().filter((book) => book.published)
),
}))
);As extensões de resource resolvem dois problemas comuns: a cintilação durante recarregamentos (corrigida por withPreviousValueOnLoading) e o tratamento de estados de erro (corrigido por withValueOnError ou withPreviousValueOnError). Essas extensões se compõem e podem ser fornecidas globalmente via provideResourceExtensions.
Gerenciamento de Entidades com withEntities
Ambas as abordagens suportam coleções de entidades, mas a funcionalidade withEntities do Signal Store reduz drasticamente o código.
import { computed, inject } from '@angular/core';
import { patchState, signalStore, withComputed, withMethods } from '@ngrx/signals';
import {
addEntity,
removeEntity,
setAllEntities,
updateEntity,
withEntities,
} from '@ngrx/signals/entities';
import { BooksService } from './books.service';
import { Book } from './book.model';
export const BooksEntityStore = signalStore(
{ providedIn: 'root' },
withEntities<Book>(),
withComputed(({ entities }) => ({
publishedBooks: computed(() => entities().filter((book) => book.published)),
})),
withMethods((store, booksService = inject(BooksService)) => ({
async loadBooks() {
const books = await booksService.getAll();
patchState(store, setAllEntities(books));
},
addBook(book: Book) {
patchState(store, addEntity(book));
},
updateBook(id: string, changes: Partial<Book>) {
patchState(store, updateEntity({ id, changes }));
},
removeBook(id: string) {
patchState(store, removeEntity(id));
},
}))
);A funcionalidade withEntities fornece automaticamente os signals ids, entityMap e entities. Os atualizadores de entidades como addEntity, removeEntity e updateEntity lidam com mutações de coleções.
Pronto para mandar bem nas entrevistas de Angular?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
Features de Store Personalizadas para Reusabilidade
A função signalStoreFeature do Signal Store permite extrair e reutilizar preocupações transversais entre stores. NgRx 22 adiciona SignalStoreFeatureType para simplificar a extração de tipos.
import { computed } from '@angular/core';
import { signalStoreFeature, withComputed, withState, SignalStoreFeatureType } from '@ngrx/signals';
type RequestStatus = 'idle' | 'pending' | 'fulfilled' | 'error';
export function withRequestStatus() {
return signalStoreFeature(
withState<{ requestStatus: RequestStatus }>({ requestStatus: 'idle' }),
withComputed(({ requestStatus }) => ({
isPending: computed(() => requestStatus() === 'pending'),
isFulfilled: computed(() => requestStatus() === 'fulfilled'),
isError: computed(() => requestStatus() === 'error'),
}))
);
}
// NgRx 22: extração de tipos sem redeclaração manual
export type RequestStatusFeature = SignalStoreFeatureType<typeof withRequestStatus>;
export function setPending(): { requestStatus: RequestStatus } {
return { requestStatus: 'pending' };
}
export function setFulfilled(): { requestStatus: RequestStatus } {
return { requestStatus: 'fulfilled' };
}
export function setError(): { requestStatus: RequestStatus } {
return { requestStatus: 'error' };
}Esta feature personalizada agora pode ser composta em qualquer store que precise de rastreamento do estado de carregamento.
import { inject } from '@angular/core';
import { patchState, signalStore, withMethods } from '@ngrx/signals';
import { setAllEntities, withEntities } from '@ngrx/signals/entities';
import { withRequestStatus, setFulfilled, setPending, setError } from './with-request-status';
import { BooksService } from './books.service';
import { Book } from './book.model';
export const BooksStore = signalStore(
{ providedIn: 'root' },
withEntities<Book>(),
withRequestStatus(),
withMethods((store, booksService = inject(BooksService)) => ({
async loadBooks() {
patchState(store, setPending());
try {
const books = await booksService.getAll();
patchState(store, setAllEntities(books), setFulfilled());
} catch {
patchState(store, setError());
}
},
}))
);O store composto agora expõe os signals computados isPending(), isFulfilled() e isError() sem duplicar lógica.
Rastreamento Síncrono do Estado com watchState
NgRx 22 adiciona a função watchState para rastreamento síncrono de mudanças de estado, útil para funcionalidades de undo/redo ou histórico de estado.
import { inject, DestroyRef } from '@angular/core';
import { watchState } from '@ngrx/signals';
import { BooksStore } from './books.store';
export function setupStateHistory() {
const store = inject(BooksStore);
const destroyRef = inject(DestroyRef);
const history: unknown[] = [];
// Rastreamento síncrono: captura cada mudança de estado, sem coalescência
watchState(store, (state) => {
history.push(structuredClone(state));
});
return { history };
}Diferente do rastreamento baseado em effects que coalesce atualizações, watchState dispara sincronamente em cada chamada patchState, capturando o histórico completo do estado.
Padrões de Integração em Componentes
Signal Store se integra naturalmente com a sintaxe de templates do Angular através de leituras de signals.
import { Component, inject } from '@angular/core';
import { BooksStore } from './books.store';
@Component({
selector: 'app-books-list',
standalone: true,
template: `
@if (store.isPending()) {
<div class="loading-spinner">Carregando livros...</div>
}
@if (store.isError()) {
<div class="error-message">Falha ao carregar livros</div>
}
@for (book of store.entities(); track book.id) {
<div class="book-card">
<h3>{{ book.title }}</h3>
<p>{{ book.author }}</p>
<button (click)="store.removeBook(book.id)">Remover</button>
</div>
}
<p>Total: {{ store.totalBooks() }} livros</p>
`,
})
export class BooksListComponent {
readonly store = inject(BooksStore);
constructor() {
this.store.loadBooks();
}
}Sem gerenciamento de subscriptions. Sem pipes async. Os signals se integram com a detecção de mudanças zoneless do Angular para performance otimizada. Com OnPush como estratégia de detecção de mudanças padrão no Angular 22, os componentes Signal Store se beneficiam de atualizações precisas e granulares.
Considerações de Performance e Tamanho de Bundle
A arquitetura mais leve do Signal Store se traduz em bundles menores. O pacote core @ngrx/signals adiciona aproximadamente 4KB comprimido com gzip, comparado com 15-20KB para o stack completo do NgRx clássico (@ngrx/store, @ngrx/effects, @ngrx/entity).
Signal Store também se beneficia da detecção de mudanças baseada em signals do Angular. Signals computados só recalculam quando as dependências mudam, e componentes só re-renderizam quando signals consumidos são atualizados. Esta reatividade granular elimina ciclos desnecessários de detecção de mudanças comuns em padrões baseados em Observables.
Para aplicações que já usam RxJS extensivamente, os selectors baseados em Observables do NgRx clássico se integram perfeitamente com pipelines existentes.
NgRx 22 requer Angular 22.x, TypeScript 6.0.x e RxJS 6.5.x ou 7.5.x. Atualizar com ng update @ngrx/signals@22 para projetos Signal Store.
Estratégia de Migração de Clássico para Signal Store
Migrar uma aplicação NgRx clássica existente não requer uma reescrita completa. Ambas as soluções podem coexistir, permitindo adoção incremental.
- Começar com novas funcionalidades usando Signal Store
- Migrar módulos de funcionalidades isolados um de cada vez
- Manter funcionalidades complexas com muitos effects no NgRx clássico se o custo de migração exceder o benefício
- Usar os utilitários de interoperabilidade do NgRx Signals para conectar estado baseado em Observables e baseado em signals
NgRx Store clássico e Signal Store podem rodar lado a lado na mesma aplicação. O time do NgRx suporta oficialmente ambas as abordagens e fornece utilitários de interoperabilidade para conectá-las.
Quando Escolher Cada Abordagem
Escolher Signal Store quando:
- Se está construindo novas aplicações Angular 22+
- Se está gerenciando estado em nível de funcionalidade ou componente
- Se está integrando com a API Resource do Angular e Signal Forms
- Experiência do desenvolvedor e redução de boilerplate são prioridade
- O time tem experiência limitada com NgRx
- O tamanho do bundle importa
Escolher NgRx Clássico quando:
- Se está mantendo aplicações NgRx existentes
- Se requer trilhas de auditoria rigorosas com logging de actions
- Se está construindo fluxos de trabalho complexos com efeitos colaterais extensivos
- Se precisa de depuração time-travel completa do Redux DevTools
- O time tem experiência profunda em NgRx
Para os fundamentos de gerenciamento de estado, entender ambas as abordagens prepara desenvolvedores para diversos codebases Angular.
Sources
- NgRx v22 Release Announcement - Extensões de resource, signals profundos dinâmicos, SignalStoreFeatureType
- Angular 22 Feature Overview - Signal Forms estável, OnPush padrão, API Resource
- Using Angular's Resource API with NgRx Signal Store - Padrões withProps, integração httpResource
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Signal Store vs NgRx Clássico: Pontos Chave
- Signal Store reduz o boilerplate de gerenciamento de estado entre 60-70% comparado com NgRx clássico
- NgRx 22 adiciona extensões de resource (
withPreviousValueOnLoading,withValueOnError) para tratamento transparente de estado assíncrono - A funcionalidade
withPropscentraliza a injeção de serviços, eliminando listas de parâmetros repetidas entre features watchStatehabilita rastreamento síncrono de estado para funcionalidades de undo/redo e histórico de estado- NgRx clássico continua sendo a melhor escolha para aplicações empresariais que requerem trilhas de auditoria rigorosas e efeitos colaterais complexos
- Ambas as abordagens coexistem na mesma aplicação, permitindo migração incremental
- Para novos projetos Angular 22+, Signal Store deve ser a escolha padrão a menos que requisitos específicos demandem NgRx clássico
Você saberia encontrar o bug em Angular?
Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Escrito por
Anthony Fillion-MailletFundador da SharpSkill
Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.
Atualizado em 9 de outubro de 2026
Compartilhar
Artigos relacionados

Trabalhos freelance como desenvolvedor Angular em 2026: onde encontrar contratos, taxas diárias, como se preparar
O mercado freelance Angular em 2026: plataformas especializadas, taxa diária mediana de 440 EUR, habilidades demandadas e preparação para entrevistas técnicas.

Vagas para desenvolvedor Angular em 2026: onde procurar, faixas salariais, como se preparar
As vagas para desenvolvedores Angular continuam abundantes na Europa no final de 2026. Descubra onde encontrar as oportunidades, os salários praticados e como se preparar para as entrevistas.

Angular Signals e Computed em 2026: Reatividade Granular e Perguntas de Entrevista
Dominar Signals do Angular, computed, effect e linkedSignal no Angular 20+. Padrões de reatividade fina e preparação para entrevistas técnicas.