Skip to main content

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.

State Nedir?
State, bir bileşenin zaman içinde değişebilen hafızasıdır. Kullanıcı etkileşimleri, API çağrıları veya zamanlayıcılar gibi olaylara yanıt olarak değişir. State değiştiğinde, React otomatik olarak bileşeni yeniden render eder ve UI'yı günceller.

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

PropsState
TanımParent'tan gelen veriBileşenin kendi verisi
Kimden gelir?Parent componentBileşenin içinde
Değiştirilebilir mi?Hayır (read-only)Evet (setState ile)
Component re-render?Parent değişirseState değişince
Kullanım amacıBileşenler arası veri aktarımıBileşen içi dinamik veri

1.1 State Olmadan Ne Olur?

NoState.tsx
1// ❌ Bu çalışmaz - değişken güncellenince UI güncellenMEZ
2function BrokenCounter() {
3 let count = 0; // Normal değişken, state değil!
4
5 function handleClick() {
6 count = count + 1;
7 console.log(count); // Console'da artıyor
8 // Ama UI güncellenmiyor çünkü React render'ı tetiklemiyor!
9 }
10
11 return (
12 <div>
13 <p>Count: {count}</p>
14 <button onClick={handleClick}>Arttır</button>
15 </div>
16 );
17}
Neden Çalışmaz?
Normal değişkenler render'lar arasında kaybolur ve değiştiğinde React yeniden render tetiklemez. UI'ın güncellenmesi için React'in state değişikliğinden haberdar olması gerekir.

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

Counter.tsx
1import { useState } from 'react';
2
3function Counter() {
4 // useState(initialValue) → [currentValue, setterFunction]
5 const [count, setCount] = useState(0);
6
7 return (
8 <div>
9 <p>Sayı: {count}</p>
10 <button onClick={() => setCount(count + 1)}>
11 Arttır
12 </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ışı

1

İ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.

tsx
1// İlk render
2const [count, setCount] = useState(0);
3// count = 0
2

Kullanıcı Etkileşimi

Kullanıcı butona tıklar. Event handler çalışır ve setCount çağrılır.

tsx
1<button onClick={() => setCount(1)}>
2 // Kullanıcı tıkladı
3 // setCount(1) çağrıldı
4</button>
3

State Güncelleme

React, yeni state değerini (1) kaydeder ve bileşeni yeniden render etmek için kuyruğa alır.

4

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.

tsx
1// İkinci render
2const [count, setCount] = useState(0);
3// count = 1 (initial değer ignore edilir)
5

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)

DirectUpdate.tsx
1function Toggle() {
2 const [isOn, setIsOn] = useState(false);
3
4 function handleToggle() {
5 // Yeni değeri doğrudan verin
6 setIsOn(!isOn);
7 }
8
9 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.

FunctionalUpdate.tsx
1function Counter() {
2 const [count, setCount] = useState(0);
3
4 function increment() {
5 // Fonksiyon olarak verin: prevState => newState
6 setCount(prevCount => prevCount + 1);
7 }
8
9 return <button onClick={increment}>Count: {count}</button>;
10}
Ne Zaman Functional Update?
  • ✅ 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

tsx
1function handleClick() {
2 setCount(count + 1); // count = 0, queue: 1
3 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}
Üç kez çağrılsa da count sadece 1 artar çünkü her satır aynı countdeğerini (0) kullanır.

4. Farklı Veri Tipleriyle State

4.1 Primitive Değerler (String, Number, Boolean)

PrimitiveState.tsx
1function UserForm() {
2 const [name, setName] = useState('');
3 const [age, setAge] = useState(0);
4 const [isActive, setIsActive] = useState(false);
5
6 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.

ObjectState.tsx
1function UserProfile() {
2 const [user, setUser] = useState({
3 name: 'Ahmet',
4 email: 'ahmet@example.com',
5 age: 25
6 });
7
8 function updateName(newName: string) {
9 setUser({
10 ...user, // Eski değerleri kopyala
11 name: newName // Sadece name'i değiştir
12 });
13 }
14
15 function updateEmail(newEmail: string) {
16 setUser(prev => ({
17 ...prev,
18 email: newEmail
19 }));
20 }
21
22 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}
ASLA Böyle Yapmayın!
tsx
1// ❌ YANLIŞ - state'i doğrudan değiştirmek
2function updateName(newName) {
3 user.name = newName; // YANLIŞ!
4 setUser(user); // React bu değişikliği fark etmez!
5}
6
7// ❌ YANLIŞ - objeyi mutate etmek
8function 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.

ArrayState.tsx
1function TodoList() {
2 const [todos, setTodos] = useState(['Alışveriş', 'Spor', 'Okuma']);
3
4 // ✅ Ekleme - spread operator
5 function addTodo(text: string) {
6 setTodos([...todos, text]);
7 // veya: setTodos(prev => [...prev, text]);
8 }
9
10 // ✅ Silme - filter
11 function removeTodo(index: number) {
12 setTodos(todos.filter((_, i) => i !== index));
13 }
14
15 // ✅ Güncelleme - map
16 function updateTodo(index: number, newText: string) {
17 setTodos(todos.map((todo, i) => i === index ? newText : todo));
18 }
19
20 // ✅ Başa ekleme
21 function prependTodo(text: string) {
22 setTodos([text, ...todos]);
23 }
24
25 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 Mutating Metodlarını Kullanmayın

Array İşlemleri

Mutating (YANLIŞ)Immutable (DOĞRU)
Eklemearr.push(item)[...arr, item]
Silmearr.pop(), arr.splice()arr.filter((_, i) => i !== index)
Güncellemearr[i] = newValuearr.map((item, i) => i === index ? new : item)
Sıralamaarr.sort()[...arr].sort()
Ters çevirmearr.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

ControlledInput.tsx
1function SearchBox() {
2 const [query, setQuery] = useState('');
3
4 return (
5 <div>
6 <input
7 type="text"
8 value={query} // State'ten gelir
9 onChange={e => setQuery(e.target.value)} // Her tuşta state güncellenir
10 placeholder="Ara..."
11 />
12 <p>Arama: {query}</p>
13 </div>
14 );
15}

5.2 Controlled Form

ControlledForm.tsx
1function RegistrationForm() {
2 const [formData, setFormData] = useState({
3 username: '',
4 email: '',
5 password: '',
6 agreeTerms: false
7 });
8
9 function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
10 const { name, value, type, checked } = e.target;
11 setFormData(prev => ({
12 ...prev,
13 [name]: type === 'checkbox' ? checked : value
14 }));
15 }
16
17 function handleSubmit(e: React.FormEvent) {
18 e.preventDefault();
19 console.log('Form data:', formData);
20 }
21
22 return (
23 <form onSubmit={handleSubmit}>
24 <input
25 name="username"
26 value={formData.username}
27 onChange={handleChange}
28 placeholder="Kullanıcı adı"
29 />
30 <input
31 name="email"
32 type="email"
33 value={formData.email}
34 onChange={handleChange}
35 placeholder="E-posta"
36 />
37 <input
38 name="password"
39 type="password"
40 value={formData.password}
41 onChange={handleChange}
42 placeholder="Şifre"
43 />
44 <label>
45 <input
46 name="agreeTerms"
47 type="checkbox"
48 checked={formData.agreeTerms}
49 onChange={handleChange}
50 />
51 Şartları kabul ediyorum
52 </label>
53 <button type="submit" disabled={!formData.agreeTerms}>
54 Kayıt Ol
55 </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.

StateLifting.tsx
1// Parent Component
2function TemperatureConverter() {
3 const [celsius, setCelsius] = useState(0);
4
5 // Celsius → Fahrenheit
6 const fahrenheit = (celsius * 9/5) + 32;
7
8 return (
9 <div>
10 <CelsiusInput value={celsius} onChange={setCelsius} />
11 <FahrenheitDisplay value={fahrenheit} />
12 </div>
13 );
14}
15
16// Child 1: Input
17function CelsiusInput({ value, onChange }) {
18 return (
19 <div>
20 <label>Celsius:</label>
21 <input
22 type="number"
23 value={value}
24 onChange={e => onChange(Number(e.target.value))}
25 />
26 </div>
27 );
28}
29
30// Child 2: Display
31function FahrenheitDisplay({ value }) {
32 return (
33 <p>Fahrenheit: {value.toFixed(2)}°F</p>
34 );
35}
State Lifting Kuralı

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

1

State'i Minimal Tutun

State'te sadece render'a etki eden verileri tutun. Türetilebilen değerleri state'e koymayın.

tsx
1// ❌ Kötü - fullName türetilebilir
2const [firstName, setFirstName] = useState('');
3const [lastName, setLastName] = useState('');
4const [fullName, setFullName] = useState(''); // Gereksiz!
5
6// ✅ İyi - fullName hesaplanır
7const [firstName, setFirstName] = useState('');
8const [lastName, setLastName] = useState('');
9const fullName = `${firstName} ${lastName}`;
2

İlgili State'leri Grupla

Birlikte güncellenen değerleri tek bir obje olarak tutun.

tsx
1// ❌ Kötü - ayrı state'ler
2const [x, setX] = useState(0);
3const [y, setY] = useState(0);
4
5// ✅ İyi - tek obje
6const [position, setPosition] = useState({ x: 0, y: 0 });
3

State'i Doğrudan Değiştirmeyin

Immutability prensibine uyun. Her zaman yeni obje/array oluşturun.

tsx
1// ❌ Kötü - mutation
2user.name = 'New Name';
3setUser(user);
4
5// ✅ İyi - yeni obje
6setUser({ ...user, name: 'New Name' });
4

Asenkron Güncellemelerde Functional Update

Önceki state'e bağlı güncellemelerde fonksiyon kullanın.

tsx
1// ⚠️ Risky
2setCount(count + 1);
3
4// ✅ Safe
5setCount(prev => prev + 1);
5

State'i Lazy Initialize Edin

Pahalı hesaplamalar varsa, lazy initialization kullanın.

tsx
1// ❌ Her render'da çalışır
2const [data, setData] = useState(expensiveCalculation());
3
4// ✅ Sadece ilk render'da çalışır
5const [data, setData] = useState(() => expensiveCalculation());

8. Yaygın State Hataları

9. Özet ve Sırada Ne Var?

Tebrikler! State Yönetimini Öğrendiniz

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
Pratik Yapın!

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
Anlayışınızı Kontrol Edin

Bir fonksiyon bileşenine state eklemek için hangi hook u kullanırsınız?

Kalan deneme: 3 / 3