React'te state yönetimi: useState, Context ve ne zaman kütüphane gerekir?
React projeleri büyüdükçe "state'i nerede tutmalıyım?" sorusu kaçınılmaz olarak gelir. Çoğu zaman cevap, düşündüğünden daha basit bir çözümdür. Redux ya da benzeri bir kütüphaneye geçmeden önce React'in kendi araçlarını doğru kullanmak birçok sorunu çözer.
1. Önce: State gerçekten state mi?
Başka değerlerden hesaplanabilen veriyi ayrı bir state olarak tutma:
// Gereksiz: filtrelenmiş liste ayrı state
const [urunler, setUrunler] = useState([]);
const [arama, setArama] = useState("");
const filtrelenmis = urunler.filter(u => u.ad.includes(arama)); // render sırasında hesapla
İki state'i senkron tutmak için useEffect yazdığını fark ediyorsan büyük olasılıkla değer hesaplanabilir demektir. Hesaplama gerçekten pahalıysa useMemo kullanabilirsin.
2. Yerel state: useState ve useReducer
Yalnızca bir bileşeni ilgilendiren state (form alanı, açık/kapalı menü) o bileşende kalmalı. Birbirine bağlı çok sayıda güncelleme varsa useReducer mantığı tek yerde toplar:
function sepetReducer(state, action) {
switch (action.type) {
case "ekle":
return [...state, action.urun];
case "cikar":
return state.filter(u => u.id !== action.id);
default:
return state;
}
}
const [sepet, dispatch] = useReducer(sepetReducer, []);
3. State'i yukarı taşımak
İki kardeş bileşen aynı veriye ihtiyaç duyuyorsa state'i en yakın ortak üst bileşene taşı ve props ile aşağı ver. Bu React'in temel desenidir.
4. Context: derin "prop drilling" için
Veri pek çok katman aşağıya iletiliyorsa (tema, oturum açmış kullanıcı, dil) Context kullanılır:
const KullaniciContext = createContext(null);
function App() {
const [kullanici, setKullanici] = useState(null);
return (
<KullaniciContext.Provider value={{ kullanici, setKullanici }}>
<Sayfa />
</KullaniciContext.Provider>
);
}
function Profil() {
const { kullanici } = useContext(KullaniciContext);
return <p>{kullanici?.ad}</p>;
}
Dikkat: Context değeri değiştiğinde onu kullanan tüm bileşenler yeniden çizilir. Sık değişen verileri (her tuş vuruşunda değişen bir değer gibi) büyük bir Context'e koymak performans sorunu yaratabilir. Gerekirse Context'leri konularına göre böl.
5. Sunucu verisi ayrı bir konu
Uygulamadaki "state"in büyük kısmı aslında sunucudan gelen veridir (ürün listesi, kullanıcı profili). Bunu useEffect + useState ile elle yönetmek; yükleniyor durumu, hata, önbellek ve yeniden getirme gibi işleri her yerde tekrar yazmak demektir. TanStack Query (React Query) ya da SWR gibi kütüphaneler bu işi çok daha temiz çözer ve çoğu projede global state ihtiyacını büyük ölçüde azaltır. Next.js gibi çatılarda sunucu bileşenleri de veri çekmenin bir parçasını üstlenir.
6. Ne zaman global state kütüphanesi?
Aşağıdakiler bir aradaysa Zustand, Redux Toolkit ya da Jotai gibi bir kütüphane düşünülebilir:
- Birbirinden uzak pek çok bileşen aynı istemci tarafı veriyi okuyup değiştiriyor (karmaşık editörler, çok adımlı formlar, sürükle-bırak arayüzler).
- Context ile gereksiz yeniden çizimler performans sorunu yaratıyor.
- Durum değişikliklerini izlemek ve hata ayıklamak için gelişmiş araçlara ihtiyaç var.
Küçük ve orta projelerde Zustand az kodla başlamak için popüler bir seçenektir; büyük ekiplerde ve katı yapı isteyen projelerde Redux Toolkit yaygındır.
Özet
- Hesaplanabilen değeri state yapma.
- State'i kullanıldığı yere en yakın yerde tut.
- Paylaşmak için önce yukarı taşı, derinse Context kullan.
- Sunucu verisi için veri çekme kütüphanesi kullan.
- Bunlar yetmiyorsa global state kütüphanesine geç.
Projende state yönetimiyle ilgili bir sorun yaşıyorsan ilgili bileşen yapısını ve kodu bu konunun altına ekleyebilirsin.