React Hooks, React 16.8 ile gelen ve functional component'lerde state ve lifecycle metodlarını kullanmamızı sağlayan özelliklerdir. Bu yazıda en önemli hook'ları ve kullanım örneklerini detaylı olarak inceleyeceğiz.
React Hooks, functional component'leri class component'ler kadar güçlü hale getirdi. Artık state yönetimi, side effects ve lifecycle metodları functional component'lerde de kullanılabiliyor.
useState Hook
useState hook'u, functional component'lerde state yönetimi için kullanılır. Bu hook sayesinde component'in state'ini tanımlayabilir ve güncelleyebiliriz.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
const [user, setUser] = useState({
firstName: '',
lastName: '',
email: ''
});
const increment = () => {
setCount(prevCount => prevCount + 1);
};
const updateUser = (field, value) => {
setUser(prevUser => ({
...prevUser,
[field]: value
}));
};
return (
Count: {count}
setName(e.target.value)}
placeholder="İsim giriniz"
/>
updateUser('firstName', e.target.value)}
placeholder="Ad"
/>
);
}
useState'in önemli noktaları:
- State güncellemeleri asenkron olarak gerçekleşir
- Object state'lerde spread operatörü kullanarak immutable güncelleme yapmalıyız
- Functional update pattern ile önceki state'e dayalı güncelleme yapabiliriz
useEffect Hook
useEffect hook'u, side effects'leri yönetmek için kullanılır. API çağrıları, DOM manipülasyonu, subscription'lar gibi işlemler için idealdir.
import React, { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// Component mount olduğunda çalışır
useEffect(() => {
fetchUserData();
}, []); // Empty dependency array
// userId değiştiğinde çalışır
useEffect(() => {
if (userId) {
fetchUserData();
}
}, [userId]);
// Cleanup function ile memory leak'leri önleriz
useEffect(() => {
const interval = setInterval(() => {
console.log('User data updated');
}, 5000);
return () => {
clearInterval(interval);
};
}, []);
const fetchUserData = async () => {
try {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
if (loading) return Yükleniyor...;
if (error) return Hata: {error};
if (!user) return Kullanıcı bulunamadı;
return (
{user.name}
{user.email}
);
}
useContext Hook
useContext hook'u, prop drilling'i önlemek ve global state'i yönetmek için kullanılır. Theme, language, user authentication gibi değerleri tüm component tree'de paylaşabiliriz.
import React, { createContext, useContext, useState } from 'react';
// Context oluşturma
const ThemeContext = createContext();
const UserContext = createContext();
// Provider component
function AppProvider({ children }) {
const [theme, setTheme] = useState('light');
const [user, setUser] = useState(null);
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
const login = (userData) => {
setUser(userData);
};
const logout = () => {
setUser(null);
};
return (
{children}
);
}
// Custom hooks
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
}
function useUser() {
const context = useContext(UserContext);
if (!context) {
throw new Error('useUser must be used within UserProvider');
}
return context;
}
// Component'lerde kullanım
function Header() {
const { theme, toggleTheme } = useTheme();
const { user, logout } = useUser();
return (
{user && (
Merhaba, {user.name}
)}
);
}
useReducer Hook
useReducer hook'u, karmaşık state logic'i için kullanılır. useState'e alternatif olarak, state güncellemelerini daha öngörülebilir hale getirir.
import React, { useReducer } from 'react';
// Action types
const ACTIONS = {
INCREMENT: 'increment',
DECREMENT: 'decrement',
RESET: 'reset',
SET_VALUE: 'set_value'
};
// Reducer function
function counterReducer(state, action) {
switch (action.type) {
case ACTIONS.INCREMENT:
return { ...state, count: state.count + 1 };
case ACTIONS.DECREMENT:
return { ...state, count: state.count - 1 };
case ACTIONS.RESET:
return { ...state, count: 0 };
case ACTIONS.SET_VALUE:
return { ...state, count: action.payload };
default:
return state;
}
}
// Initial state
const initialState = {
count: 0,
history: []
};
function CounterWithReducer() {
const [state, dispatch] = useReducer(counterReducer, initialState);
const increment = () => {
dispatch({ type: ACTIONS.INCREMENT });
};
const decrement = () => {
dispatch({ type: ACTIONS.DECREMENT });
};
const reset = () => {
dispatch({ type: ACTIONS.RESET });
};
const setValue = (value) => {
dispatch({ type: ACTIONS.SET_VALUE, payload: parseInt(value) });
};
return (
Count: {state.count}
setValue(e.target.value)}
placeholder="Değer giriniz"
/>
);
}
Custom Hooks
Custom hook'lar, logic'i yeniden kullanılabilir hale getirmek için mükemmel bir yöntemdir. Kendi hook'larımızı oluşturarak kod tekrarını önleyebiliriz.
import { useState, useEffect, useCallback } from 'react';
// Custom hook: API data fetching
function useApi(url, options = {}) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetchData = useCallback(async () => {
try {
setLoading(true);
setError(null);
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, [url, JSON.stringify(options)]);
useEffect(() => {
fetchData();
}, [fetchData]);
const refetch = () => {
fetchData();
};
return { data, loading, error, refetch };
}
// Custom hook: Local storage
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
// Custom hook: Window size
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight
});
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}
// Component'lerde kullanım
function UserList() {
const { data: users, loading, error, refetch } = useApi('/api/users');
const [theme, setTheme] = useLocalStorage('theme', 'light');
const { width, height } = useWindowSize();
if (loading) return Yükleniyor...;
if (error) return Hata: {error};
return (
Kullanıcılar ({users.length})
Ekran boyutu: {width}x{height}
{users.map(user => (
{user.name}
))}
);
}
useMemo ve useCallback
useMemo ve useCallback hook'ları, performance optimizasyonu için kullanılır. Gereksiz re-render'ları önleyerek uygulamanın performansını artırırlar.
import React, { useState, useMemo, useCallback } from 'react';
function ExpensiveComponent({ items, filterText }) {
// Expensive calculation'ı memoize et
const filteredItems = useMemo(() => {
console.log('Filtering items...');
return items.filter(item =>
item.name.toLowerCase().includes(filterText.toLowerCase())
);
}, [items, filterText]);
// Callback'i memoize et
const handleItemClick = useCallback((itemId) => {
console.log('Item clicked:', itemId);
// Item click logic
}, []);
return (
Filtrelenmiş Öğeler: {filteredItems.length}
{filteredItems.map(item => (
handleItemClick(item.id)}
style={{ cursor: 'pointer' }}
>
{item.name}
))}
);
}
function ParentComponent() {
const [items, setItems] = useState([
{ id: 1, name: 'React' },
{ id: 2, name: 'Vue' },
{ id: 3, name: 'Angular' }
]);
const [filterText, setFilterText] = useState('');
const [count, setCount] = useState(0);
// items array'ini memoize et
const memoizedItems = useMemo(() => items, [items]);
return (
setFilterText(e.target.value)}
placeholder="Filtrele..."
/>
);
}
Best Practices ve Öneriler
React Hooks kullanırken dikkat edilmesi gereken önemli noktalar:
- Hook'ları sadece component'in en üst seviyesinde çağırın - loops, conditions veya nested functions içinde kullanmayın
- Custom hook'ları "use" ile başlatın - Bu, React'in hook kurallarını uygulamasını sağlar
- Dependency array'leri doğru kullanın - useEffect ve useMemo'da gerekli tüm dependencies'leri ekleyin
- Cleanup functions kullanın - useEffect'te return statement ile cleanup yapın
- Performance optimizasyonlarını gereksiz yere kullanmayın - useMemo ve useCallback'i sadece gerekli olduğunda kullanın
Sonuç
React Hooks, modern React geliştirmenin temel taşlarından biridir. Bu hook'lar sayesinde:
- Functional component'lerde state yönetimi yapabiliyoruz
- Side effects'leri temiz bir şekilde yönetebiliyoruz
- Logic'i yeniden kullanılabilir hale getirebiliyoruz
- Performance optimizasyonları yapabiliyoruz
- Daha temiz ve okunabilir kod yazabiliyoruz
Hooks'ları öğrenmek ve doğru kullanmak, modern React uygulamaları geliştirmek için kritik öneme sahiptir. Bu yazıda öğrendiğiniz hook'ları projelerinizde kullanarak daha güçlü ve maintainable uygulamalar geliştirebilirsiniz.