React'te bileşen state'ini yönetmek için en yaygın kullanılan iki hook useState ve useReducer'dır. Her ikisi de state'i güncellemeye ve bileşenin yeniden render edilmesini sağlamaya yarar, ancak farklı karmaşıklık ve öngörülebilirlik seviyelerinde çalışır. Peki hangi durumda hangisini kullanmalısınız? İşte bu sorunun cevabını, pratik örnekler ve karşılaştırmalarla adım adım inceleyelim.
useState ve useReducer Arasındaki Temel Farklar
İki hook arasındaki farkı anlamak, doğru aracı seçmek için kritik öneme sahiptir. Aşağıdaki tabloda temel farklılıkları özetliyoruz:
| Özellik | useState | useReducer |
|---|---|---|
| State tipi | Herhangi bir değer (sayı, string, obje, dizi) | Genellikle obje veya karmaşık veri yapıları |
| Güncelleme şekli | Doğrudan yeni değer atanır veya fonksiyon ile önceki değer kullanılır | Action (eylem) objesi ile reducer fonksiyonu aracılığıyla |
| Karmaşıklık | Basit, tek değerler için idealdir | Daha karmaşık, birden fazla alt değer içeren state'ler için uygundur |
| Test edilebilirlik | Bileşen içinde test edilir | Reducer fonksiyonu bağımsız test edilebilir |
| Performans | Basit durumlarda aynıdır, ancak sık güncellemelerde useReducer daha optimize edilebilir | Reducer mantığı değişmiyorsa aynı referansı korur, bu da child component'lerde gereksiz render'ı önleyebilir |
Gördüğünüz gibi useReducer, daha yapılandırılmış bir state yönetimi sunarken, useState basit ve hızlı çözümler için yeterlidir.
Hangi Durumda useState Kullanmalısınız?
useState, aşağıdaki senaryolar için en uygun seçimdir:
- Tekil ve bağımsız değerler: Örneğin bir form input'u, sayaç veya görünürlük durumu.
- State güncellemeleri birbirinden bağımsız olduğunda: Her state parçası ayrı ayrı güncelleniyorsa useState ile yönetmek daha kolaydır.
- Az sayıda state değişkeni varsa: 2-3'ten fazla state değişkeni olduğunda useReducer daha mantıklı hale gelir.
- Basit ve hızlı prototiplerde: Karmaşık bir yapıya ihtiyaç yoksa useState kodu daha kısa ve okunabilir kılar.
Örneğin, bir kullanıcı adı input'u için const [username, setUsername] = useState(''); kullanımı gayet iş görür.
Hangi Durumda useReducer Kullanmalısınız?
useReducer ise daha karmaşık state mantığı gerektiğinde devreye girer:
- State birden fazla alt değer içeriyorsa: Örneğin bir form state'i (name, email, password, errors, isSubmitting gibi).
- Bir sonraki state, önceki state'e bağlı olarak karmaşık bir şekilde hesaplanıyorsa: Birden fazla işlem adımı gerekiyorsa.
- State güncelleme mantığı bağımsız test edilmek istendiğinde: Reducer fonksiyonunu saf JavaScript fonksiyonu olarak yazıp test edebilirsiniz.
- State geçişleri belirli bir eylem türüne bağlı olduğunda: Örneğin, API çağrılarında loading, success, error durumları.
Bir API çağrısı örneğini düşünelim: loading, data, error gibi üç farklı durumu yönetmek için useReducer ideal bir seçimdir. Aynı zamanda REST API'lerde standart hata kodları ve anlamlı hata mesajları oluşturmak için reducer içinde bu durumları merkezi olarak kontrol edebilirsiniz. Daha fazla bilgi için REST API'lerde Standart Hata Kodları ve Anlamlı Hata Mesajları başlıklı yazımıza göz atabilirsiniz.
Pratik Örnek: Bir API Çağrısının State Yönetimi
Kullanıcı verilerini çeken bir bileşen düşünelim. useState ile tipik yaklaşım şöyle olur:
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
Ancak bu üç ayrı state değişkeni arasındaki geçişleri yönetmek zorlaşabilir. Örneğin, bir hata durumunda loading'i sıfırlamayı unutabilirsiniz. useReducer ile tek bir state objesi kullanarak tüm durumları merkezileştirebiliriz:
const initialState = { loading: false, data: null, error: null };
function fetchReducer(state, action) {
switch (action.type) {
case 'FETCH_START':
return { ...state, loading: true, error: null };
case 'FETCH_SUCCESS':
return { loading: false, data: action.payload, error: null };
case 'FETCH_ERROR':
return { loading: false, error: action.payload };
default:
return state;
}
}
const [state, dispatch] = useReducer(fetchReducer, initialState);
Bu yaklaşım hem daha öngörülebilir hem de daha az hata içerir. API isteklerinde rate limiting gibi konuları da yönetmek istiyorsanız, REST API Rate Limiting yazımızda detaylı bilgi bulabilirsiniz.
Sık Yapılan Hatalar ve İpuçları
- Her state için ayrı useState kullanmak: Birden fazla state değişkeni birbiriyle ilişkiliyse, bunları tek bir useReducer'da birleştirmek hem performans hem de okunabilirlik açısından daha iyidir.
- useReducer'ı karmaşıklaştırmak: Reducer'da çok fazla action type tanımlamak kodu şişirebilir. Basit tutun, gerekirse alt reducet'ler kullanın.
- Reducer'ı mutasyona uğratmak: Reducer fonksiyonunun saf kalması gerekir; state veya action'ı mutasyona uğratmayın, her zaman yeni obje döndürün.
- useState ile useReducer'ı karıştırmak: Aynı bileşende her iki hook'u da kullanmak mümkün olsa da, tüm state yönetimini tek bir yaklaşımla tutarlı yapmak daha iyidir.
State yönetimi yaparken güvenlik de önemlidir. Özellikle kimlik doğrulama içeren uygulamalarda JWT token'larını yönetmek için useReducer kullanabilirsiniz. REST API'lerde JWT ile Güvenli Kimlik Doğrulama yazımızda bu konuya değiniyoruz.
Kısaca Özetlemek Gerekirse
useState basit, bağımsız state parçaları için idealken, useReducer karmaşık, ilişkili state'ler ve öngörülebilir güncellemeler gerektiğinde tercih edilmelidir. Projenizin ihtiyaçlarını değerlendirin: Eğer birkaç tekil değer yönetiyorsanız useState yeterli olacaktır; ancak state'iniz büyüyüp birden fazla alt değer ve geçiş durumu içeriyorsa useReducer size daha temiz ve test edilebilir bir yapı sunar. Unutmayın, her iki hook da React'in state yönetimindeki en önemli araçlarıdır ve doğru yerde kullanıldıklarında uygulamanızın kalitesini artırır.
Sık Sorulan Sorular
useState ve useReducer arasındaki temel fark nedir?
useState doğrudan bir değer atayarak state güncellerken, useReducer bir reducer fonksiyonu ve eylem (action) kullanarak state'i günceller. useReducer daha karmaşık state yapıları ve öngörülebilir güncellemeler için uygundur.
useReducer ne zaman kullanılmalı?
State birden fazla alt değer içeriyorsa, güncelleme mantığı karmaşıksa veya state geçişleri belirli eylem türlerine bağlıysa (örneğin API çağrısı durumları) useReducer kullanmak idealdir.
Basit bir sayaç için hangisi daha iyi?
Basit bir sayaç için useState yeterlidir. useReducer aynı işi yapabilir ancak gereksiz karmaşıklık ekler.
useState ile useReducer aynı anda kullanılabilir mi?
Evet, aynı bileşende her iki hook da kullanılabilir. Ancak tutarlılık için tüm state yönetimini tek bir yaklaşımla sürdürmek önerilir.
useReducer performans açısından daha mı iyidir?
Genellikle aynı performansa sahiptir, ancak useReducer referans kararlılığı sayesinde child component'lerde gereksiz render'ları önleyebilir. Karmaşık state'lerde edge case'lerde fark yaratabilir.






