NgRx Signal Store vs Klasik NgRx 2026: Hangisini Seçmelisiniz?
Angular durum yönetimi için NgRx Signal Store ve Klasik NgRx kapsamli karsilastirmasi. NgRx 22 özellikleri ile pratik kod örnekleri ve tavsiyeler.

NgRx Signal Store, geleneksel Redux tabanli aksiyonlar-reducer'lar-selectorlar kalibini sinyal tabanli reaktif bir yaklasimla degistirerek Angular durum yonetiminde temel bir degisimi temsil etmektedir. NgRx 22 (Agustos 2026'da yayinlandi) ile Signal Store, kaynak uzantilari, dinamik deep signal'lar ve iyilestirilmis birlestirilebilirlik kazanmaktadir. Bu karsilastirma, Angular gelistiricilerinin bilinçli mimari kararlar vermelerine yardimci olmak için her iki çözümü incelemektedir.
Özellik düzeyinde durum, orta karmasiklikta uygulamalar ve Angular'in yerel Resource API entegrasyonu için Signal Store kullanilmalidir. Siki denetim izleri, karmasik yan etkiler ve kapsamli DevTools hata ayiklamasi gerektiren kurumsal uygulamalar için Klasik NgRx kullanilmalidir.
Mimari Farkliliklari Anlama
Klasik NgRx, Redux kalibi üzerine kuruludur: aksiyonlar olaylari tanimlar, reducer'lar yeni degismez durum üretir ve selectorlar verileri çikarir. Her durum degisikligi öngörülebilir, izlenebilir bir boru hattindan geçer.
Signal Store farkli bir yaklasim benimser. Aksiyonlari reducer'lar araciligiyla göndermek yerine, durum reaktif sinyallerde yasir. Güncellemeler patchState() çagiran metodlar araciligiyla gerçeklesir ve türetilmis degerler memoize edilmis selectorlar yerine computed signal'lardan gelir.
| Yön | Klasik NgRx | Signal Store |
|---|---|---|
| Zihinsel Model | Redux/Flux | Reaktif Servisler |
| Boilerplate | Yüksek (aksiyonlar, reducer'lar, selectorlar, efektler) | Düsük (durum, metodlar, computed) |
| Reaktivite | RxJS Observable'lar | Angular Signal'lar |
| Resource API | Manuel entegrasyon | @ngrx/signals/resource ile yerel |
| DevTools | Tam Redux DevTools | Signal Store DevTools (eklenti ile) |
| Ögrenme Egrisi | Dik | Orta |
| Bundle Boyutu | Daha Büyük (~15-20KB gzip) | Daha Küçük (~4KB gzip) |
Angular Signals'a zaten asina olan gelistiriciler için Signal Store, framework'ün reaktif ilkellerinin dogal bir uzantisi gibi hissedilir.
Klasik NgRx: Angular'da Redux Kalibi
Klasik NgRx, durum yönetimini aksiyonlar, reducer'lar, selectorlar ve efektler etrafinda organize eder. Bu ayrim, uzunluk pahasina öngörülebilirligi zorlar.
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 }>(),
},
});createActionGroup API'si ilgili aksiyonlari tek bir kaynak altinda gruplar, DevTools okunabilirligini artirir ve ayri createAction çagrilarina kiyasla boilerplate'i azaltir.
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,
}))
);Reducer'lar yeni durum nesneleri döndüren saf fonksiyonlar olarak kalir. on() fonksiyonu aksiyon eslestirmeyi ve durum güncellemelerini özlü bir sekilde yönetir.
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)
);Selectorlar otomatik olarak memoizasyon saglar. selectPublishedBooks selectoru sadece kitaplar dizisi degistiginde yeniden hesaplanir, bu da sik güncellenen store'larda bile okumalari verimli kilar.
NgRx Signal Store: Sinyal Öncelikli Durum Yönetimi
Signal Store, durumu, computed degerleri ve metodlari tek bir enjekte edilebilir servis içinde birlestirir. Resmi NgRx dokümantasyonu bunu "Angular Signals için yerel destekli, tam özellikli bir durum yönetimi çözümü" olarak tanimlar.
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),
}));
},
}))
);Tüm özelligin durum yönetimi tek bir dosyaya sigar. Durum özellikleri otomatik olarak sinyal olur, computed signal'lar selectorlarin yerini alir ve metodlar aksiyon gönderimlerinin yerini alir.
NgRx 22: Kaynak Uzantilari ve withProps
NgRx 22, Angular'in Resource API'si ile dogrudan entegrasyonu saglayan @ngrx/signals/resource giris noktasini tanitir. withProps özelligi servis enjeksiyonunu merkezilestirirken, kaynak uzantilari yaygin asenkron kaliplari ele alir.
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' },
// Servisleri withProps ile enjekte et (alt çizgi ile özel kural geregi)
withProps(() => ({
_booksService: inject(BooksService),
})),
// Uzantilarla kaynaklari yapilandir
withProps((store) => ({
_booksResource: extendResource(
httpResource<Book[]>({
url: '/api/books',
defaultValue: [],
}),
withPreviousValueOnLoading(), // Yeniden yüklerken son degeri korur
withValueOnError([]) // Hata durumunda bos dizi döndürür
),
})),
// Tüketicilere salt okunur kaynak sun
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)
),
}))
);Kaynak uzantilari iki yaygin sorunu çözer: yeniden yüklemelerde titreme (withPreviousValueOnLoading ile düzeltilir) ve hata durumu yönetimi (withValueOnError veya withPreviousValueOnError ile düzeltilir). Bu uzantilar birlestirilebilir ve provideResourceExtensions ile global olarak saglanabilir.
withEntities ile Varlik Yönetimi
Her iki yaklasim da varlik koleksiyonlarini destekler, ancak Signal Store'un withEntities özelligi kodu önemli ölçüde azaltir.
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));
},
}))
);withEntities özelligi otomatik olarak ids, entityMap ve entities sinyallerini saglar. addEntity, removeEntity ve updateEntity gibi varlik güncelleyicileri koleksiyon mutasyonlarini yönetir.
Angular mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
Yeniden Kullanilabilirlik için Özel Store Özellikleri
Signal Store'un signalStoreFeature fonksiyonu, kesisen ilgi alanlarinin çikartilmasini ve farkli store'larda yeniden kullanilmasini saglar. NgRx 22, tip çikartmayi basitlestirmek için SignalStoreFeatureType ekler.
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: manuel yeniden bildirim olmadan tip çikartma
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' };
}Bu özel özellik artik yükleme durumu izlemesi gerektiren herhangi bir store'a eklenebilir.
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());
}
},
}))
);Birlesmis store artik mantigi çogaltmadan isPending(), isFulfilled() ve isError() computed signal'larini açiga çikarir.
watchState ile Senkron Durum Izleme
NgRx 22, geri alma/yineleme islevi veya durum geçmisi için yararli olan senkron durum degisikligi izleme için watchState fonksiyonunu ekler.
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[] = [];
// Senkron izleme: her durum degisikligini yakalar, birlestirme yok
watchState(store, (state) => {
history.push(structuredClone(state));
});
return { history };
}Güncellemeleri birlestiren efekt tabanli izlemenin aksine, watchState her patchState çagrisinda senkron olarak tetiklenir ve tam durum geçmisini yakalar.
Bilesen Entegrasyon Kaliplari
Signal Store, sinyal okumalari araciligiyla Angular'in sablon sözdizimi ile dogal olarak bütünlesir.
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">Kitaplar yükleniyor...</div>
}
@if (store.isError()) {
<div class="error-message">Kitaplar yüklenemedi</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)">Kaldir</button>
</div>
}
<p>Toplam: {{ store.totalBooks() }} kitap</p>
`,
})
export class BooksListComponent {
readonly store = inject(BooksStore);
constructor() {
this.store.loadBooks();
}
}Abonelik yönetimi yok. Async pipe'lar yok. Sinyaller, optimum performans için Angular'in zoneless degisiklik algilamasi ile bütünlesir. Angular 22'nin varsayilan OnPush degisiklik algilama stratejisi ile Signal Store bilesenleri hassas, granüler güncellemelerden yararlanir.
Performans ve Bundle Boyutu Degerlendirmeleri
Signal Store'un daha hafif mimarisi daha küçük bundle'lara dönüsür. Çekirdek @ngrx/signals paketi yaklasik 4KB gzip eklerken, tam klasik NgRx yigini (@ngrx/store, @ngrx/effects, @ngrx/entity) 15-20KB ekler.
Signal Store ayrica Angular'in sinyal tabanli degisiklik algilamasindan da yararlanir. Computed signal'lar yalnizca bagimliliklar degistiginde yeniden hesaplanir ve bilesenler yalnizca tüketilen sinyaller güncellendiginde yeniden render edilir. Bu granüler reaktivite, Observable tabanli kaliplarda yaygin olan gereksiz degisiklik algilama döngülerini ortadan kaldirir.
Halihazirda yogun RxJS kullanan uygulamalar için, klasik NgRx'in Observable tabanli selectorlari mevcut boru hatlariyla sorunsuzca bütünlesir.
NgRx 22, Angular 22.x, TypeScript 6.0.x ve RxJS 6.5.x veya 7.5.x gerektirir. Signal Store projeleri için ng update @ngrx/signals@22 ile güncelleme yapin.
Klasikten Signal Store'a Migrasyon Stratejisi
Mevcut bir klasik NgRx uygulamasini tasimak büyük bir yeniden yazim gerektirmez. Her iki çözüm bir arada var olabilir ve kademeli benimsemeyi mümkün kilar.
- Signal Store kullanarak yeni özelliklerle baslamak
- Izole özellik modüllerini birer birer tasimak
- Migrasyon maliyeti faydasini asarsa, karmasik, efekt agirlikli özellikleri klasik NgRx'te tutmak
- Observable tabanli ve sinyal tabanli durum arasinda köprü kurmak için NgRx Signals interop yardimci programlarini kullanmak
Klasik NgRx Store ve Signal Store ayni uygulamada yan yana çalisabilir. NgRx ekibi her iki yaklasimi da resmi olarak destekler ve aralarinda köprü kurmak için interop yardimci programlari saglar.
Her Yaklasimi Ne Zaman Seçmeli
Signal Store'u su durumlarda seçin:
- Yeni Angular 22+ uygulamalari olusturma
- Özellik düzeyinde veya bilesen düzeyinde durum yönetimi
- Angular'in Resource API ve Signal Forms ile entegrasyon
- Gelistirici deneyimi ve azaltilmis boilerplate önceliklendirme
- Ekibin sinirli NgRx deneyimi var
- Bundle boyutu önemli
Klasik NgRx'i su durumlarda seçin:
- Mevcut NgRx uygulamalarinin bakimi
- Siki aksiyon günlükleme ve denetim izleri gereksinimi
- Kapsamli yan etkilerle karmasik is akislari olusturma
- Tam Redux DevTools zaman yolculugu hata ayiklamasi gereksinimi
- Ekibin derin NgRx uzmanligi var
Durum yönetimi temelleri her iki yaklasimda da gelistiricileri çesitli Angular kod tabanlarina hazirlar.
Kaynaklar
- NgRx v22 Release Announcement - Kaynak uzantilari, dinamik deep signal'lar, SignalStoreFeatureType
- Angular 22 Feature Overview - Signal Forms stabil, OnPush varsayilan, Resource API
- Using Angular's Resource API with NgRx Signal Store - withProps kaliplari, httpResource entegrasyonu
Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Signal Store vs Klasik NgRx: Temel Çikarimlar
- Signal Store, klasik NgRx'e kiyasla durum yönetimi boilerplate'ini %60-70 azaltir
- NgRx 22, sorunsuz asenkron durum yönetimi için kaynak uzantilari (
withPreviousValueOnLoading,withValueOnError) ekler withPropsözelligi, özellikler arasinda tekrarlanan parametre listelerini ortadan kaldirarak servis enjeksiyonunu merkezilestirwatchState, geri alma/yineleme ve durum geçmisi için senkron durum izlemeyi saglar- Klasik NgRx, siki denetim izleri ve karmasik yan etkiler gerektiren kurumsal uygulamalar için daha iyi seçim olmaya devam eder
- Her iki yaklasim ayni uygulamada bir arada var olabilir ve kademeli migrasyonu mümkün kilar
- Yeni Angular 22+ projeleri için, belirli gereksinimler klasik NgRx'i gerektirmedikçe Signal Store varsayilan seçim olmalidir
Angular kodundaki hatayı bulabilir misin?
Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Yazan:
Anthony Fillion-MailletSharpSkill kurucusu
10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.
9 Ekim 2026 tarihinde güncellendi
Etiketler
Paylaş
İlgili makaleler

Angular'da RxJS 2026: Operatörler, Subject'ler ve Signals Interop
Angular'da RxJS 2026: üretimde kullanılan operatörleri, Subject'leri ve Signals interop kalıplarını öğrenin, ayrıca en sık karşılaşılan mülakat sorularını.

Angular Resource API ve httpResource: Kapsamli Rehber (Angular 22'de Stabil)
Angular'in Resource API ve httpResource ozellikleri Angular 22 itibariyle stabil hale geldi. Bu rehber resource(), rxResource(), httpResource(), bagimli kaynaklar icin yeni chain() helper'i, Zod dogrulamasi ve mulakat sorularini kapsiyor.

2026'da İleri Düzey Angular Dependency Injection: Providers, Tokens ve Mülakat Soruları
Angular'da ileri düzey Dependency Injection mekanizmalarına kapsamlı bir bakış. Providers, InjectionToken, injector hiyerarşisi ve teknik mülakatlarda karşılaşılan sorular.