04 / 12
State
useState, snapshot ve updater, immutable güncelleme, state'i doğru kurmak ve state türleri.
State Nedir
State, bir component'in render'lar arasında hatırladığı veridir. useState iki şey döndürür: o anki değer ve onu güncelleyen fonksiyon. Güncelleme fonksiyonu çağrıldığında React component'i yeniden render eder.1
import { useState } from "react";
export function QuantityPicker() {
const [quantity, setQuantity] = useState(1);
return (
<div>
<button onClick={() => setQuantity(quantity - 1)}>-</button>
<span>{quantity}</span>
<button onClick={() => setQuantity(quantity + 1)}>+</button>
</div>
);
}Normal bir let değişkeni bu işi göremez: her render fonksiyonu baştan çalıştırır ve değişkeni sıfırlar, üstelik değişkeni değiştirmek render'ı tetiklemez.1
State Bir Fotoğraftır
setQuantity değeri hemen değiştirmez; bir sonraki render için istek bırakır. O render'ın içindeki quantity sabit kalır.2
function handleAddThree() {
setQuantity(quantity + 1);
setQuantity(quantity + 1);
setQuantity(quantity + 1);
console.log(quantity); // hâlâ 1; sonuç: 2
}Üç çağrı da 1 + 1 hesaplar. React aynı event'teki güncellemeleri toplu işler (batching) ve tek bir render yapar. Önceki değere göre güncelleme yapıyorsanız updater fonksiyonu verin:2
setQuantity((q) => q + 1); // sonuç: 4
setQuantity((q) => q + 1);
setQuantity((q) => q + 1);Josh W. Comeau bu "set ettim ama eski değeri görüyorum" durumunu yeni başlayanların en sık takıldığı hatalardan biri olarak sayar.3
Değiştirmeyin, Yenisini Verin
Obje ya da dizi tutan state'i doğrudan değiştirmeyin. React değişikliği referans karşılaştırmasıyla anlar; aynı objeyi değiştirip geri verirseniz render olmayabilir.4
// ❌ mutasyon
cart.push(product);
setCart(cart);
// ✅ yeni dizi
setCart([...cart, product]);
setCart(cart.filter((item) => item.id !== id));
setCart(cart.map((item) =>
item.id === id ? { ...item, quantity: item.quantity + 1 } : item,
));push, splice, sort ve reverse diziyi yerinde değiştirir; toSorted ve toReversed gibi kopya döndüren karşılıklarını ya da spread'i kullanın.4 eslint-plugin-react-hooks'un immutability kuralı props ve state mutasyonunu yakalar.5
State'i Doğru Kurmak
Hataların çoğu state'in kendisinden değil, yanlış kurulmasından çıkar. React dokümanının beş ilkesi:6
| İlke | Örnek |
|---|---|
| Birlikte değişenleri birleştirin | x ve y yerine position |
| Çelişkiye izin vermeyin | isLoading + isError yerine status: "idle" | "loading" | "error" |
| Hesaplanabileni tutmayın | fullName state değil, firstName + lastName |
| Kopyalamayın | Seçili ürünün kendisi değil selectedId |
| Derin iç içe yapıdan kaçının | Ağaç yerine düz liste ve id'ler |
Üçüncü ilke en sık bozulandır. TkDodo bir kod incelemesinde hep aynı kalıbı gördüğünü anlatıyor: veriden kategori listesini çıkarıp ayrı bir state'e koyan ve bir Effect ile senkron tutan kod. Sonra biri setCategories'i başka yerden çağırınca kategoriler veriden kopuyor. Kuralı kısa: bir state setter'ı yalnızca bir Effect içinde senkron çağrılıyorsa o state'i silin.7 Kent C. Dodds da aynı kuralı tek cümleyle söylüyor: "State'i senkronlamayın, türetin."8
// ❌ İki state, bir Effect
const [products, setProducts] = useState<Product[]>([]);
const [inStock, setInStock] = useState<Product[]>([]);
useEffect(() => {
setInStock(products.filter((p) => p.stock > 0));
}, [products]);
// ✅ Bir state, bir hesap
const [products, setProducts] = useState<Product[]>([]);
const inStock = products.filter((p) => p.stock > 0);Hesap pahalıysa bile önce ölçün; memoization'ı React Compiler ya da useMemo halleder.
State Nerede Durur, Ne Zaman Sıfırlanır
State, onu kullanan en yakın ortak ebeveyne konur. İki kardeş aynı değere ihtiyaç duyuyorsa state ebeveyne çıkar ve props olarak iner.9 Karar tablosu ve colocation Component ve Kod Organizasyonu rehberinde.
React state'i component'e değil, component'in ağaçtaki yerine bağlar. Aynı yerde aynı tipte component render edildikçe state korunur; component kaldırılınca ya da tipi değişince silinir.10 Aynı yerde farklı bir kaydı gösterirken state'i sıfırlamak için key verin: <ReviewForm key={product.id} />.10
useState mi, useReducer mı?
Güncellemeler birçok yerden geliyor ve birbirine bağlıysa (çok adımlı form, sepet) useReducer mantığı tek bir saf fonksiyonda toplar ve test edilmesini kolaylaştırır.11 TkDodo'nun ölçütü: birbirinden bağımsız değişen değerler için ayrı useState, birlikte değişen ve birbirine bağlı parçalar için useReducer.12 Tipli bir cartReducer örneği React'te tipler dersinde.
Her Veri Aynı State Değil
Kent C. Dodds, uygulama state'ini en az iki türe ayırmayı önerir: sunucudan gelen veri (server cache) ve yalnızca arayüzü yöneten veri (UI state). İkisini aynı yerde tutmak en büyük karmaşa kaynağıdır.13
| Tür | Örnek | Nerede |
|---|---|---|
| UI state | Modal açık mı, seçili sekme | useState, gerekirse Context |
| Server state | Ürün listesi, sipariş | TanStack Query ya da framework |
| URL state | Arama metni, filtre, sayfa | Router'ın search params'ı |
| Form state | Henüz gönderilmemiş girdiler | Form, Formlar rehberi |
| Paylaşılan client state | Tema, sepet | Context ya da Zustand |
Kendin Dene
QuantityPicker'a "+3" butonu ekleyin. Öncequantity + 1ile, sonra updater ile yazın.Sepetteki bir ürünün adedini
item.quantity++ile artırmayı deneyin ve ekranın neden güncellenmediğini açıklayın.isLoading,isErrorvedatatutan bir component'i tek birstatusalanına çevirin.Bir ürün listesinde
filteredProducts'ı state'ten çıkarıp render sırasında hesaplayın.
Detaylı Öğrenmek İçin
Resmi doküman: "Managing State" bölümü; state yapısı, state'i yukarı taşıma ve state'i koruma/sıfırlama.610
Yazı: TkDodo'nun "useState pitfalls" serisi; türetilmiş state ve props'u state'e koymak.7
Yazı: Kent C. Dodds'un "Application State Management with React" yazısı; server cache ile UI state ayrımı.13
Kaynaklar
`useState`, yerel değişkenin neden yetmediği.
Render içindeki state'in sabit kalması; batching ve updater için "Queueing a Series of State Updates" sayfası.
: — State'i değiştirdikten hemen sonra okumak ve mutasyon hataları.
Mutasyon yapan ve yeni dizi döndüren metotlar tablosu.
Props ve state mutasyonunu yakalayan kural.
Gruplama, çelişki, gereksiz state, kopyalama ve iç içe yapı ilkeleri.
: — 29 Ağustos 2020. Türetilmiş state ve Effect ile senkronlamanın riski.
: — 30 Eylül 2019. Tic-tac-toe örneğiyle hesaplanabilen değeri state'te tutmamak.
State'i en yakın ortak ebeveyne taşımak.
State'in ağaçtaki konuma bağlı olması ve `key` ile sıfırlama.
`useReducer`'a geçiş ve `useState` ile karşılaştırma.
: — 2021, Nisan 2022'de güncellendi. Birlikte değişen state ve reducer kullanımı.
: — 2020. Server cache ile UI state'i ayırmak ve colocation.
Son güncelleme tarihi: 21 Ekim 2026
