React State: Bileşenleri Canlı Hale Getirin
State, React bileşenlerinize hafıza ve interaktivite kazandırır. Bu derste useState hook'unu öğrenecek ve gerçek dünya uygulamalarıyla pratik yapacaksınız.
1. State Kavramını Anlamak
React'te state, bileşenin renderlar arasında hatırladığı değerlerdir. Düşünün ki bir sayaç var: butona her tıkladığınızda değer artıyor. Bu değerin bir yerde saklanması ve değiştiğinde UI'ın güncellenmesi gerekir. İşte state bunun için vardır.
Props vs State
| Props | State | |
|---|---|---|
| Tanım | Parent'tan gelen veri | Bileşenin kendi verisi |
| Kimden gelir? | Parent component | Bileşenin içinde |
| Değiştirilebilir mi? | Hayır (read-only) | Evet (setState ile) |
| Component re-render? | Parent değişirse | State değişince |
| Kullanım amacı | Bileşenler arası veri aktarımı | Bileşen içi dinamik veri |
1.1 State Olmadan Ne Olur?
1// ❌ Bu çalışmaz - değişken güncellenince UI güncellenMEZ2function BrokenCounter() {3 let count = 0; // Normal değişken, state değil!45 function handleClick() {6 count = count + 1;7 console.log(count); // Console'da artıyor8 // Ama UI güncellenmiyor çünkü React render'ı tetiklemiyor!9 }1011 return (12 <div>13 <p>Count: {count}</p>14 <button onClick={handleClick}>Arttır</button>15 </div>16 );17}
2. useState Hook: Temel Kullanım
useState hook'u, fonksiyon bileşenlerine state eklemek için React'in sağladığı bir araçtır. İki değer döndürür: mevcut state ve onu güncelleyen fonksiyon.
2.1 İlk State Değişkeniniz
1import { useState } from 'react';23function Counter() {4 // useState(initialValue) → [currentValue, setterFunction]5 const [count, setCount] = useState(0);67 return (8 <div>9 <p>Sayı: {count}</p>10 <button onClick={() => setCount(count + 1)}>11 Arttır12 </button>13 </div>14 );15}
useState Anatomisi
- useState(0)
- Hook çağrısı. Parantez içindeki 0, initial (başlangıç) değeridir. İlk render'da count bu değeri alır.
- [count, setCount]
- Array destructuring. useState bir dizi döndürür: [0] mevcut değer, [1] setter fonksiyon. İsimleri istediğiniz gibi verebilirsiniz.
- count
- Mevcut state değeri. Bu değeri JSX'te kullanabilir, if statement'lerde kontrol edebilir, başka fonksiyonlara gönderebilirsiniz.
- setCount
- State'i güncelleyen fonksiyon. Çağırdığınızda React yeniden render tetikler. Genelde "set" + state ismi formatında adlandırılır.
- Re-render
- setCount çağrıldığında, React component fonksiyonunu tekrar çalıştırır (re-render). Bu sefer count yeni değeri alır ve UI güncellenir.
2.2 useState Nasıl Çalışır?
useState Akışı
İlk Render
Component ilk kez render edildiğinde, useState(0) çağrılır. React bu bileşen için state oluşturur ve initial değeri (0) saklar.
1// İlk render2const [count, setCount] = useState(0);3// count = 0
Kullanıcı Etkileşimi
Kullanıcı butona tıklar. Event handler çalışır ve setCount çağrılır.
1<button onClick={() => setCount(1)}>2 // Kullanıcı tıkladı3 // setCount(1) çağrıldı4</button>
State Güncelleme
React, yeni state değerini (1) kaydeder ve bileşeni yeniden render etmek için kuyruğa alır.
Re-render
React component fonksiyonunu tekrar çalıştırır. Bu sefer useStateinitial değer yerine güncel değeri (1) döndürür.
1// İkinci render2const [count, setCount] = useState(0);3// count = 1 (initial değer ignore edilir)
UI Güncellenir
Yeni JSX render edilir ve DOM'a uygulanır. Kullanıcı güncel değeri görür.
3. State Güncelleme Pattern'leri
3.1 Direct Update (Doğrudan Güncelleme)
1function Toggle() {2 const [isOn, setIsOn] = useState(false);34 function handleToggle() {5 // Yeni değeri doğrudan verin6 setIsOn(!isOn);7 }89 return (10 <button onClick={handleToggle}>11 {isOn ? 'Açık' : 'Kapalı'}12 </button>13 );14}
3.2 Functional Update (Fonksiyonel Güncelleme)
Eğer yeni state, önceki state'e bağlıysa, functional update kullanmalısınız. Bu, asenkron güncellemelerde doğru değeri garanti eder.
1function Counter() {2 const [count, setCount] = useState(0);34 function increment() {5 // Fonksiyon olarak verin: prevState => newState6 setCount(prevCount => prevCount + 1);7 }89 return <button onClick={increment}>Count: {count}</button>;10}
- ✅ Yeni state, önceki state'e bağlıysa:
setCount(c => c + 1) - ✅ Birden fazla güncelleme aynı anda oluyorsa
- ✅ Event handler içinde closure sorunu yaşıyorsanız
- ⚠️ Basit atamalar için:
setName('John')yeterli
3.3 Dikkat: Birden Fazla Güncelleme
1function handleClick() {2 setCount(count + 1); // count = 0, queue: 13 setCount(count + 1); // count = 0, queue: 1 (tekrar!)4 setCount(count + 1); // count = 0, queue: 1 (tekrar!)5 // Sonuç: count = 1 (3 değil!)6}
countdeğerini (0) kullanır.4. Farklı Veri Tipleriyle State
4.1 Primitive Değerler (String, Number, Boolean)
1function UserForm() {2 const [name, setName] = useState('');3 const [age, setAge] = useState(0);4 const [isActive, setIsActive] = useState(false);56 return (7 <div>8 <input value={name} onChange={e => setName(e.target.value)} />9 <input type="number" value={age} onChange={e => setAge(Number(e.target.value))} />10 <input type="checkbox" checked={isActive} onChange={e => setIsActive(e.target.checked)} />11 </div>12 );13}
4.2 Object State (Obje Durumu)
Object state kullanırken immutability (değişmezlik) prensibi çok önemlidir. State'i asla doğrudan değiştirmeyin, her zaman yeni bir obje oluşturun.
1function UserProfile() {2 const [user, setUser] = useState({3 name: 'Ahmet',4 email: 'ahmet@example.com',5 age: 256 });78 function updateName(newName: string) {9 setUser({10 ...user, // Eski değerleri kopyala11 name: newName // Sadece name'i değiştir12 });13 }1415 function updateEmail(newEmail: string) {16 setUser(prev => ({17 ...prev,18 email: newEmail19 }));20 }2122 return (23 <div>24 <input value={user.name} onChange={e => updateName(e.target.value)} />25 <input value={user.email} onChange={e => updateEmail(e.target.value)} />26 </div>27 );28}
1// ❌ YANLIŞ - state'i doğrudan değiştirmek2function updateName(newName) {3 user.name = newName; // YANLIŞ!4 setUser(user); // React bu değişikliği fark etmez!5}67// ❌ YANLIŞ - objeyi mutate etmek8function updateAge() {9 user.age = 26; // YANLIŞ!10 // Re-render tetiklenmez!11}
4.3 Array State (Dizi Durumu)
Array state'i güncellerken de immutability önemlidir. push, pop, splice gibi mutating metodlar yerine map, filter, spread operator kullanın.
1function TodoList() {2 const [todos, setTodos] = useState(['Alışveriş', 'Spor', 'Okuma']);34 // ✅ Ekleme - spread operator5 function addTodo(text: string) {6 setTodos([...todos, text]);7 // veya: setTodos(prev => [...prev, text]);8 }910 // ✅ Silme - filter11 function removeTodo(index: number) {12 setTodos(todos.filter((_, i) => i !== index));13 }1415 // ✅ Güncelleme - map16 function updateTodo(index: number, newText: string) {17 setTodos(todos.map((todo, i) => i === index ? newText : todo));18 }1920 // ✅ Başa ekleme21 function prependTodo(text: string) {22 setTodos([text, ...todos]);23 }2425 return (26 <ul>27 {todos.map((todo, i) => (28 <li key={i}>29 {todo}30 <button onClick={() => removeTodo(i)}>Sil</button>31 </li>32 ))}33 </ul>34 );35}
Array İşlemleri
| Mutating (YANLIŞ) | Immutable (DOĞRU) | |
|---|---|---|
| Ekleme | arr.push(item) | [...arr, item] |
| Silme | arr.pop(), arr.splice() | arr.filter((_, i) => i !== index) |
| Güncelleme | arr[i] = newValue | arr.map((item, i) => i === index ? new : item) |
| Sıralama | arr.sort() | [...arr].sort() |
| Ters çevirme | arr.reverse() | [...arr].reverse() |
5. Controlled Components (Kontrollü Bileşenler)
Controlled component, değeri React state'inden gelen bir form elementidir. Bu yaklaşım, form verileriniz üzerinde tam kontrol sağlar.
5.1 Controlled Input
1function SearchBox() {2 const [query, setQuery] = useState('');34 return (5 <div>6 <input7 type="text"8 value={query} // State'ten gelir9 onChange={e => setQuery(e.target.value)} // Her tuşta state güncellenir10 placeholder="Ara..."11 />12 <p>Arama: {query}</p>13 </div>14 );15}
5.2 Controlled Form
1function RegistrationForm() {2 const [formData, setFormData] = useState({3 username: '',4 email: '',5 password: '',6 agreeTerms: false7 });89 function handleChange(e: React.ChangeEvent<HTMLInputElement>) {10 const { name, value, type, checked } = e.target;11 setFormData(prev => ({12 ...prev,13 [name]: type === 'checkbox' ? checked : value14 }));15 }1617 function handleSubmit(e: React.FormEvent) {18 e.preventDefault();19 console.log('Form data:', formData);20 }2122 return (23 <form onSubmit={handleSubmit}>24 <input25 name="username"26 value={formData.username}27 onChange={handleChange}28 placeholder="Kullanıcı adı"29 />30 <input31 name="email"32 type="email"33 value={formData.email}34 onChange={handleChange}35 placeholder="E-posta"36 />37 <input38 name="password"39 type="password"40 value={formData.password}41 onChange={handleChange}42 placeholder="Şifre"43 />44 <label>45 <input46 name="agreeTerms"47 type="checkbox"48 checked={formData.agreeTerms}49 onChange={handleChange}50 />51 Şartları kabul ediyorum52 </label>53 <button type="submit" disabled={!formData.agreeTerms}>54 Kayıt Ol55 </button>56 </form>57 );58}
6. State Lifting (State'i Yukarı Taşıma)
Bazen birden fazla bileşenin aynı state'i paylaşması gerekir. Bu durumda state'i ortak parent component'e taşırsınız. Bu pattern'e "lifting state up" denir.
1// Parent Component2function TemperatureConverter() {3 const [celsius, setCelsius] = useState(0);45 // Celsius → Fahrenheit6 const fahrenheit = (celsius * 9/5) + 32;78 return (9 <div>10 <CelsiusInput value={celsius} onChange={setCelsius} />11 <FahrenheitDisplay value={fahrenheit} />12 </div>13 );14}1516// Child 1: Input17function CelsiusInput({ value, onChange }) {18 return (19 <div>20 <label>Celsius:</label>21 <input22 type="number"23 value={value}24 onChange={e => onChange(Number(e.target.value))}25 />26 </div>27 );28}2930// Child 2: Display31function FahrenheitDisplay({ value }) {32 return (33 <p>Fahrenheit: {value.toFixed(2)}°F</p>34 );35}
State her zaman onu kullanan tüm bileşenlerin ortak parent'ında olmalıdır:
- 🔼 State yukarı taşınır (lift up)
- 📤 Veri props olarak aşağı aktarılır (pass down)
- 📞 Child'lar callback fonksiyonlarla state'i günceller
7. State Best Practices
State Kullanımında En İyi Pratikler
State'i Minimal Tutun
State'te sadece render'a etki eden verileri tutun. Türetilebilen değerleri state'e koymayın.
1// ❌ Kötü - fullName türetilebilir2const [firstName, setFirstName] = useState('');3const [lastName, setLastName] = useState('');4const [fullName, setFullName] = useState(''); // Gereksiz!56// ✅ İyi - fullName hesaplanır7const [firstName, setFirstName] = useState('');8const [lastName, setLastName] = useState('');9const fullName = `${firstName} ${lastName}`;
İlgili State'leri Grupla
Birlikte güncellenen değerleri tek bir obje olarak tutun.
1// ❌ Kötü - ayrı state'ler2const [x, setX] = useState(0);3const [y, setY] = useState(0);45// ✅ İyi - tek obje6const [position, setPosition] = useState({ x: 0, y: 0 });
State'i Doğrudan Değiştirmeyin
Immutability prensibine uyun. Her zaman yeni obje/array oluşturun.
1// ❌ Kötü - mutation2user.name = 'New Name';3setUser(user);45// ✅ İyi - yeni obje6setUser({ ...user, name: 'New Name' });
Asenkron Güncellemelerde Functional Update
Önceki state'e bağlı güncellemelerde fonksiyon kullanın.
1// ⚠️ Risky2setCount(count + 1);34// ✅ Safe5setCount(prev => prev + 1);
State'i Lazy Initialize Edin
Pahalı hesaplamalar varsa, lazy initialization kullanın.
1// ❌ Her render'da çalışır2const [data, setData] = useState(expensiveCalculation());34// ✅ Sadece ilk render'da çalışır5const [data, setData] = useState(() => expensiveCalculation());
8. Yaygın State Hataları
9. Özet ve Sırada Ne Var?
Bu derste şunları öğrendiniz:
- ✅ State kavramı ve React'te nasıl çalıştığı
- ✅ useState hook ile state oluşturma ve güncelleme
- ✅ Primitive, object ve array state yönetimi
- ✅ Functional update pattern ve asenkron güncellemeler
- ✅ Controlled components ve form handling
- ✅ State lifting ve component iletişimi
- ✅ Immutability prensibi ve neden önemli olduğu
- ✅ Best practices ve yaygın hatalardan kaçınma
Sırada Ne Var?
Bir sonraki derslerde useEffect, custom hooks, context API ve performans optimizasyonları gibi ileri seviye konulara dalacağız.
- 🎯 useEffect ile side effects yönetimi
- 🎯 Custom hooks oluşturma
- 🎯 Context API ile global state
- 🎯 useMemo ve useCallback ile performans
State öğrenmenin en iyi yolu pratik yapmaktır. Şimdi kendi projelerinizi oluşturun:
- 📝 Bir sayaç uygulaması yapın (increment, decrement, reset)
- 📝 Todo list oluşturun (ekle, sil, işaretle)
- 📝 Form validasyonu ekleyin
- 📝 Shopping cart mantığı kodlayın
- 📝 Quiz uygulaması yapın