Ders İçeriği
State Nedir? Neden Kullanılır?
State (durum), React bileşenlerinin dinamik verilerini saklamak ve yönetmek için kullanılan temel bir kavramdır. State, bir bileşenin içindeki değişebilen verileri temsil eder ve bu veriler değiştiğinde bileşen otomatik olarak yeniden render edilir.
State'in temel özellikleri:
Değişebilirlik: State verileri zaman içinde değişebilir. Kullanıcı etkileşimleri, API çağrıları veya zamanlayıcılar gibi olaylar sonucunda state güncellenebilir.
Yerellik: Her bileşenin kendi state'i vardır ve bu state sadece o bileşen tarafından doğrudan değiştirilebilir. Bu, veri yönetimini daha öngörülebilir hale getirir.
Reaktivite: State değiştiğinde, React otomatik olarak bileşeni yeniden render eder ve kullanıcı arayüzü güncel verilerle güncellenir.
Neden State Kullanırız?
State olmadan, React bileşenleri sadece statik içerik gösterebilir. Ancak gerçek dünya uygulamalarında, kullanıcı etkileşimlerine yanıt vermek, form verilerini yönetmek, API'lerden gelen verileri göstermek gibi dinamik işlemler yapmamız gerekir. İşte bu noktada state devreye girer.
Örneğin, bir sayaç uygulaması düşünün. Sayaç değeri değişmeli ve bu değişiklik ekranda görünmelidir. State kullanmadan bu mümkün değildir:
// State olmadan - Bu çalışmaz!
function Counter() {
let count = 0; // Bu değer değişse bile bileşen yeniden render edilmez
return (
<div>
<p>Sayaç: {count}</p>
<button onClick={() => count++}>Artır</button>
</div>
);
}
State Kullanımı (useState Hook'u)
Modern React'te, fonksiyonel bileşenlerde state yönetimi için useState
Hook'u kullanılır. Bu Hook, state değişkeni ve bu değişkeni güncellemek için bir fonksiyon döndürür.
Temel useState Kullanımı
import React, { useState } from 'react';
function Counter() {
// useState Hook'u ile state tanımlama
const [count, setCount] = useState(0);
return (
<div>
<p>Sayaç: {count}</p>
<button onClick={() => setCount(count + 1)}>Artır</button>
<button onClick={() => setCount(count - 1)}>Azalt</button>
<button onClick={() => setCount(0)}>Sıfırla</button>
</div>
);
}
useState
Hook'unun yapısı:
- İlk parametre: State'in başlangıç değeri
- Döndürdüğü değerler: Bir dizi içinde iki element
- İlk element: Mevcut state değeri
- İkinci element: State'i güncellemek için kullanılan fonksiyon
Farklı Veri Tipleri ile State
State sadece sayılar için değil, her türlü JavaScript veri tipi için kullanılabilir:
function UserProfile() {
// String state
const [name, setName] = useState('');
// Boolean state
const [isLoggedIn, setIsLoggedIn] = useState(false);
// Array state
const [hobbies, setHobbies] = useState([]);
// Object state
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
return (
<div>
<h2>Kullanıcı Profili</h2>
<p>İsim: {name}</p>
<p>Giriş Durumu: {isLoggedIn ? 'Giriş Yapılmış' : 'Giriş Yapılmamış'}</p>
<p>Hobiler: {hobbies.join(', ')}</p>
<p>Kullanıcı: {user.name} - {user.email}</p>
</div>
);
}
State Güncelleme Kuralları
State'i güncellerken dikkat edilmesi gereken önemli kurallar vardır:
1. State'i Doğrudan Değiştirmeyin:
// Yanlış - State'i doğrudan değiştirme
function WrongExample() {
const [user, setUser] = useState({ name: 'Ahmet', age: 25 });
const updateAge = () => {
user.age = 26; // Bu yanlış!
setUser(user); // Bu da çalışmayacak
};
return <button onClick={updateAge}>Yaşı Güncelle</button>;
}
// Doğru - Yeni obje oluşturma
function CorrectExample() {
const [user, setUser] = useState({ name: 'Ahmet', age: 25 });
const updateAge = () => {
setUser({ ...user, age: 26 }); // Spread operator ile yeni obje
};
return <button onClick={updateAge}>Yaşı Güncelle</button>;
}
2. Array State Güncelleme:
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = (text) => {
// Yeni todo ekleme
setTodos([...todos, { id: Date.now(), text, completed: false }]);
};
const removeTodo = (id) => {
// Todo silme
setTodos(todos.filter(todo => todo.id !== id));
};
const toggleTodo = (id) => {
// Todo durumunu değiştirme
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
return (
<div>
{todos.map(todo => (
<div key={todo.id}>
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
{todo.text}
</span>
<button onClick={() => toggleTodo(todo.id)}>Tamamla</button>
<button onClick={() => removeTodo(todo.id)}>Sil</button>
</div>
))}
<button onClick={() => addTodo('Yeni görev')}>Görev Ekle</button>
</div>
);
}
Props Nedir? Neden Kullanılır?
Props (properties), React bileşenlerine dışarıdan veri aktarmak için kullanılan mekanizmadır. Props, bir bileşenin parametreleri gibi düşünülebilir. Üst bileşen (parent), alt bileşene (child) props aracılığıyla veri gönderebilir.
Props'un temel özellikleri:
Salt Okunur (Read-Only): Props, alan bileşen tarafından değiştirilemez. Bu, tek yönlü veri akışını sağlar ve uygulamanın öngörülebilirliğini artırır.
Dışarıdan Gelen Veri: Props, bileşenin dışından gelen verilerdir. Bu sayede aynı bileşen farklı verilerle yeniden kullanılabilir.
Herhangi Bir Veri Tipi: Props olarak string, number, boolean, array, object, function gibi herhangi bir JavaScript veri tipi gönderilebilir.
Props Kullanımı (Veri Aktarımı)
Temel Props Kullanımı
// Alt bileşen - props alır
function Greeting(props) {
return <h1>Merhaba, {props.name}!</h1>;
}
// Üst bileşen - props gönderir
function App() {
return (
<div>
<Greeting name="Ahmet" />
<Greeting name="Fatma" />
<Greeting name="Mehmet" />
</div>
);
}
Destructuring ile Props Kullanımı
Props'u daha temiz bir şekilde kullanmak için destructuring yapılabilir:
// Destructuring ile props alma
function UserCard({ name, email, avatar, isOnline }) {
return (
<div className="user-card">
<img src={avatar} alt={`${name} avatar`} />
<h3>{name}</h3>
<p>{email}</p>
<span className={`status ${isOnline ? 'online' : 'offline'}`}>
{isOnline ? 'Çevrimiçi' : 'Çevrimdışı'}
</span>
</div>
);
}
// Kullanımı
function UserList() {
return (
<div>
<UserCard
name="Ahmet Yılmaz"
email="ahmet@example.com"
avatar="avatar1.jpg"
isOnline={true}
/>
<UserCard
name="Fatma Kaya"
email="fatma@example.com"
avatar="avatar2.jpg"
isOnline={false}
/>
</div>
);
}
Default Props
Bileşenlere varsayılan props değerleri verilebilir:
function Button({ text, color, size, onClick }) {
return (
<button
className={`btn btn-${color} btn-${size}`}
onClick={onClick}
>
{text}
</button>
);
}
// Default props tanımlama
Button.defaultProps = {
text: 'Tıkla',
color: 'primary',
size: 'medium',
onClick: () => {}
};
// Modern yaklaşım - destructuring ile default değerler
function Button({
text = 'Tıkla',
color = 'primary',
size = 'medium',
onClick = () => {}
}) {
return (
<button
className={`btn btn-${color} btn-${size}`}
onClick={onClick}
>
{text}
</button>
);
}
Fonksiyon Props
Props olarak fonksiyonlar da gönderilebilir. Bu, alt bileşenin üst bileşenle iletişim kurmasını sağlar:
function SearchBox({ onSearch, placeholder }) {
const [query, setQuery] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
onSearch(query); // Üst bileşene veri gönderme
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder={placeholder}
/>
<button type="submit">Ara</button>
</form>
);
}
function App() {
const [searchResults, setSearchResults] = useState([]);
const handleSearch = (query) => {
// Arama işlemi yapılır
console.log('Aranan:', query);
// API çağrısı yapılabilir
// setSearchResults(results);
};
return (
<div>
<SearchBox
onSearch={handleSearch}
placeholder="Ne aramak istiyorsunuz?"
/>
{/* Arama sonuçları gösterimi */}
</div>
);
}
Tek Yönlü Veri Akışı
React'te veri akışı tek yönlüdür: üst bileşenden alt bileşene doğru. Bu, uygulamanın veri yönetimini daha öngörülebilir ve hata ayıklamasını daha kolay hale getirir.
Veri Akışı Prensibi
function App() {
const [users, setUsers] = useState([
{ id: 1, name: 'Ahmet', email: 'ahmet@example.com' },
{ id: 2, name: 'Fatma', email: 'fatma@example.com' }
]);
const addUser = (newUser) => {
setUsers([...users, { ...newUser, id: Date.now() }]);
};
const deleteUser = (userId) => {
setUsers(users.filter(user => user.id !== userId));
};
return (
<div>
<UserForm onAddUser={addUser} />
<UserList users={users} onDeleteUser={deleteUser} />
</div>
);
}
function UserList({ users, onDeleteUser }) {
return (
<div>
<h2>Kullanıcı Listesi</h2>
{users.map(user => (
<UserItem
key={user.id}
user={user}
onDelete={() => onDeleteUser(user.id)}
/>
))}
</div>
);
}
function UserItem({ user, onDelete }) {
return (
<div className="user-item">
<span>{user.name} - {user.email}</span>
<button onClick={onDelete}>Sil</button>
</div>
);
}
function UserForm({ onAddUser }) {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (name && email) {
onAddUser({ name, email });
setName('');
setEmail('');
}
};
return (
<form onSubmit={handleSubmit}>
<h2>Yeni Kullanıcı Ekle</h2>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="İsim"
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="E-posta"
/>
<button type="submit">Ekle</button>
</form>
);
}
State Yukarı Taşıma (Lifting State Up)
Birden fazla bileşenin aynı state'i paylaşması gerektiğinde, state ortak üst bileşene taşınır:
function TemperatureCalculator() {
const [temperature, setTemperature] = useState('');
const [scale, setScale] = useState('c');
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius}
onTemperatureChange={(temp) => {
setTemperature(temp);
setScale('c');
}}
/>
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={(temp) => {
setTemperature(temp);
setScale('f');
}}
/>
<BoilingVerdict celsius={parseFloat(celsius)} />
</div>
);
}
function TemperatureInput({ scale, temperature, onTemperatureChange }) {
const scaleName = scale === 'c' ? 'Celsius' : 'Fahrenheit';
return (
<fieldset>
<legend>{scaleName} cinsinden sıcaklık girin:</legend>
<input
value={temperature}
onChange={(e) => onTemperatureChange(e.target.value)}
/>
</fieldset>
);
}
function BoilingVerdict({ celsius }) {
if (celsius >= 100) {
return <p>Su kaynar.</p>;
}
return <p>Su kaynamaz.</p>;
}
// Yardımcı fonksiyonlar
function toCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}
function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000;
return rounded.toString();
}
Bu örnekte, sıcaklık değeri ve ölçek bilgisi üst bileşende (TemperatureCalculator) tutulur ve alt bileşenlere props olarak geçirilir. Bu sayede her iki input alanı da senkronize kalır ve su kaynatma durumu doğru şekilde hesaplanır.
State ve props, React'in temel yapı taşlarıdır. State bileşenlerin dinamik verilerini yönetirken, props bileşenler arası veri aktarımını sağlar. Bu iki kavramı doğru şekilde kullanmak, etkili React uygulamaları geliştirmenin anahtarıdır.