STATE YÖNETİMİ STRATEJİSİ SEÇMEK VE UYGULAMAK
React projesi büyüdükçe en çok tartışılan konu genellikle şuna döner: “State’i nereye koyacağız?” Bir form alanı, bir filtre, bir sepet, bir kullanıcı oturumu… Hepsini aynı yere yığmak hem hatayı artırır hem de ekip içinde geliştirme hızını düşürür. Tam tersi şekilde her şeyi parçalara bölmek de yönetimi zorlaştırabilir.
İyi bir state yönetimi stratejisi, tek bir araç seçmekten çok daha fazlasıdır. Amaç; veri akışını anlaşılır kılmak, gereksiz güncellemeleri azaltmak ve değişiklikleri güvenle yapmak. Bu rehberde, React’in yerleşik araçlarını (useState, useReducer, context) doğru konumlandırmayı; ihtiyaç varsa store yaklaşımını mantıklı bir çerçevede ele almayı anlatacağız.
Uygulamalı örnekler, kod kalıpları ve ekip içinde ortak dil oluşturma adımları için react eğitimi içeriğine de göz atabilirsiniz.

State kapsamını doğru belirlemek ve sınır çizmek
Stratejinin başlangıç noktası, state’in kapsadığı alanı netleştirmektir. “Bu veri sadece bu bileşeni mi ilgilendiriyor, yoksa sayfanın farklı yerleri de mi kullanıyor?” sorusu, ilk ayrımı yapmayı sağlar. Çoğu durumda çözüm, state’i en yakın ihtiyaç noktasına koymak ve yalnızca gerektiğinde yukarı taşımaktır.
Burada iki yaygın yanılgı vardır: (1) “Her şeyi en üstte tutarsak kolay olur” yaklaşımı; (2) “Her şeyi local tutarsak performans kazanırız” yaklaşımı. İkisi de tek başına doğru değildir. Ölçüt, değişimin kimleri etkilediği ve iş kuralının nerede yaşadığı olmalıdır.
Local state kullanarak hızlı ilerlemek ve karmaşayı azaltmak
Input değerleri, aç/kapa durumları, geçici UI tercihleri gibi veriler için local state genellikle en doğru çözümdür. Bu veriler sayfa yenilenince zaten sıfırlanabilir ve başka bileşenler tarafından kullanılmaz. Local state, bağımlılığı azaltır ve değişikliği daha izole hale getirir.
Lifting state up kararını veriye göre almak ve yönetmek
Aynı veri birden fazla kardeş bileşeni etkiliyorsa state’i ortak parent’a taşımak gerekir. Ancak bu taşıma, “parent her render’da her şeyi hareketlendirmesin” diye bileşen sınırlarını iyi kurmayı da gerektirir. Bu noktada memoization, prop tasarımı ve bileşen bölme gibi tekniklerle birlikte düşünmek önemlidir.
Derived state yaklaşımını doğru uygulamak ve sadeleştirmek
Derived state, başka bir state’ten hesaplanan veridir. Örneğin “filtrelenmiş liste” çoğu zaman “liste + filtre” ile hesaplanabilir. Bunu ayrıca state’te tutmak; senkronizasyon hataları, gereksiz güncellemeler ve test zorluğu getirir. Sade bir yaklaşım, derived veriyi render sırasında üretmek ve gerektiğinde useMemo ile optimize etmektir.
Kaynak state’i tek tutup hesaplamayı kontrollü yapmak
Tek “source of truth” tutmak, hata ayıklamayı kolaylaştırır. “Neden liste yanlış çıktı?” sorusu tek bir kaynağa iner. Hesaplama pahalıysa memoization ile korunur; ama state’i çoğaltarak yönetim yükü artırılmaz.
useMemo ile hesaplamayı sınırlamak ve stabil tutmak
useMemo, her şeyi hızlandırmak için değil, pahalı işlemleri gereksiz tekrar etmemek için kullanılır. Burada dependency listesini doğru kurmak gerekir. Aksi halde hesaplamayı yanlış zamanda sabitlemek, beklenmedik sonuçlara yol açabilir.
import React, { useMemo, useState } from "react";
export default function Products({ items }) {
const [query, setQuery] = useState("");
const [onlyInStock, setOnlyInStock] = useState(false);
const filtered = useMemo(() => {
const q = query.trim().toLowerCase();
return items
.filter(x => (onlyInStock ? x.stock > 0 : true))
.filter(x => (q ? x.title.toLowerCase().includes(q) : true));
}, [items, query, onlyInStock]);
return (
<div>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<label>
<input
type="checkbox"
checked={onlyInStock}
onChange={(e) => setOnlyInStock(e.target.checked)}
/>
Stokta olanlar
</label>
<div>Sonuç: {filtered.length}</div>
</div>
);
}useReducer ile iş kurallarını merkezileştirmek ve test etmek
State karmaşıklaştığında (çoklu alan, çoklu aksiyon, doğrulama, adım adım akış) useState zincirleri hızla dağınık hale gelir. Bu tür durumlarda useReducer, güncellemeleri tek bir “aksiyon” sözlüğüne toplar ve davranışı netleştirir. Ayrıca reducer mantığı, UI’dan daha bağımsız test edilebilir.
Action tabanlı düşünerek değişimi izlemek ve yönetmek
Reducer, “ne oldu?” sorusuna cevap veren aksiyonlar üzerinden ilerler. Bu yaklaşım, ekip içinde ortak dil kurmayı sağlar. Örneğin “ADD_ITEM”, “REMOVE_ITEM”, “APPLY_COUPON” gibi aksiyonlar, hem loglamayı hem de hata ayıklamayı kolaylaştırır.
Reducer yapısını küçük tutmak ve büyütmeyi planlamak
Reducer’ı tek bir dev fonksiyona çevirmek yerine, alanlara göre bölmek ve ortak yardımcılarla ilerlemek önemlidir. Böylece yeni özellik eklemek, mevcut davranışı kırmadan yapılabilir. Ayrıca side effect’leri (API çağrıları gibi) reducer’ın dışına taşımak daha sağlıklıdır.
import React, { useReducer } from "react";
const initial = { items: [], coupon: null, note: "" };
function cartReducer(state, action) {
switch (action.type) {
case "ADD_ITEM":
return { ...state, items: [...state.items, action.payload] };
case "REMOVE_ITEM":
return { ...state, items: state.items.filter(x => x.id !== action.payload) };
case "APPLY_COUPON":
return { ...state, coupon: action.payload };
case "SET_NOTE":
return { ...state, note: action.payload };
default:
return state;
}
}
export default function Cart() {
const [state, dispatch] = useReducer(cartReducer, initial);
return (
<div>
<button onClick={() => dispatch({ type: "ADD_ITEM", payload: { id: 1, title: "Tişört" } })}>
Ürün ekle
</button>
<input
placeholder="Sipariş notu"
value={state.note}
onChange={(e) => dispatch({ type: "SET_NOTE", payload: e.target.value })}
/>
<div>Sepet: {state.items.length} ürün</div>
</div>
);
}Context kullanımını doğru sınırlandırmak ve performansı korumak
Context, “prop drilling” sorununu azaltır; ama yanlış kullanılırsa geniş kapsamlı yeniden render dalgaları yaratabilir. Bu yüzden context’i “her şeyin deposu” gibi görmek yerine, belirli alanlar için net sınırlarla kullanmak gerekir.
Context’i bölerek güncellemeyi daraltmak ve izole etmek
Tek bir provider altında kullanıcı, tema, sepet ve izinler birleşirse; küçük bir değişim birçok tüketiciyi etkileyebilir. Daha iyi bir yaklaşım, context’i alanlara ayırmak (ör. AuthContext, ThemeContext, CartContext) ve provider’ları ihtiyaca göre bileşen ağacında doğru yerde konumlandırmaktır.
Provider value referansını stabilize etmek ve kontrol etmek
Context value her render’da yeni obje olursa, tüketiciler tekrar çalışabilir. Provider value’sunu useMemo ile sabitlemek, gereksiz güncellemeleri azaltabilir. Burada hedef; gerçek değişim olduğunda güncellemek, diğer durumlarda stabil kalmaktır.

Global store kararını doğru vermek ve entegrasyon planlamak
Bazı projelerde, birden fazla sayfa arasında paylaşılan karmaşık veri akışı vardır: oturum, yetkiler, feature flag’ler, sepet, favoriler, offline kuyruk gibi. Bu noktada store yaklaşımı (Redux, Zustand vb.) gündeme gelebilir. Buradaki kritik nokta, “store kullanmak” değil, hangi problem için kullanmaktır.
Hangi veri global olmalı sorusunu netleştirmek ve sınırlandırmak
Global veri; sayfalar arası kalıcılık, birden çok bağımsız alanın aynı veriye ihtiyaç duyması veya olay bazlı güncellemeler gibi ihtiyaçlar doğurduğunda anlam kazanır. Aksi halde her şeyi store’a taşımak, bileşenleri gereksiz bağımlı hale getirir. İyi bir strateji, globali küçük tutup lokal alanları korumaktır.
Store entegrasyonunu adımlı yapmak ve risk azaltmak
Yeni bir store’u bir günde tüm projeye yaymak yerine, önce tek bir alan (ör. sepet) seçip standardı orada oturtmak daha güvenli olur. Aksiyon isimlendirmesi, selector yazımı, hata loglama ve devtool kullanımı netleşince ölçeklemek kolaylaşır. Bu yaklaşım, ekip içinde ortak davranış geliştirmeyi de hızlandırır.
Strateji dokümantasyonunu oluşturmak ve sürdürülebilir yapmak
State yönetimi, yalnızca kod değil aynı zamanda ekip içi anlaşmadır. Herkes farklı bir yaklaşım benimsediğinde, proje ilerledikçe tutarlılık kaybolur. Bu yüzden temel kararları kısa bir rehberde toparlamak, uzun vadede maliyeti düşürür.
Ortak karar setini maddelerle belirlemek ve paylaşmak
Aşağıdaki kontrol listesi, “hangi aracı ne zaman kullanıyoruz?” sorusuna hızlı yanıt verir. Listeyi proje ihtiyaçlarına göre uyarlayıp sürümlemek, ekip içinde kalıcı bir standarda dönüşmesini sağlar.
- UI geçici verileri local state ile taşımak
- Sayfa içi paylaşım için lifting state up uygulamak
- Karmaşık akış için useReducer ile aksiyon tanımlamak
- Geniş paylaşım için context’i bölerek kullanmak
- Çok sayfalı kalıcılık için store ihtiyacını gerekçelendirmek
- Hesaplanan verileri derived state yerine memoize etmek
Performans ve hata ayıklamayı rutine eklemek ve iyileştirmek
Stratejinin işe yaradığını anlamanın yolu ölçmektir. Profiler ile render dalgalarını görmek, reducer aksiyonlarını loglamak ve context güncellemelerini izlemek, hata ayıklamayı hızlandırır. Böylece “seçtiğimiz yaklaşım ölçekliyor mu?” sorusuna veriye dayalı cevap üretmek mümkün olur.

Kapanış: Sağlam bir state yönetimi stratejisi; local state’i doğru kullanmak, derived state’i sade tutmak, karmaşık iş kurallarını reducer ile toplamak, context’i sınırlandırmak ve gerekirse store’u hedefli devreye almakla oluşur. Bu kararları ekip içinde ortak dile çevirip dokümante etmek de sürdürülebilirliği artırır. Daha fazla pratik ve örnek senaryo için react eğitimi sayfasını inceleyebilirsiniz.


