React'te state yönetimi, özellikle karmaşık mantık ve birden fazla alt değer içeren durumlarda zorlaşabilir. useReducer hook'u, bu tür senaryolar için useState'e göre daha yapılandırılmış ve öngörülebilir bir çözüm sunar. Bir reducer fonksiyonu ve başlangıç değeri alarak, state güncellemelerini merkezi bir şekilde yönetmenizi sağlar.
Neden useReducer Kullanmalısınız?
useReducer, özellikle aşağıdaki durumlarda avantajlıdır:
- State birden fazla alt değer içeriyorsa (örn. form verileri, kullanıcı profili)
- Bir state güncellemesi diğerine bağlıysa (örn. alışveriş sepeti toplamı)
- State geçişleri belirli kurallara tabiyse (örn. onay kutusu, sihirbaz adımları)
- Performans kritikse ve gereksiz yeniden render'ları önlemek istiyorsanız
Bu yapı sayesinde state değişiklikleri daha test edilebilir ve hata ayıklaması kolay hale gelir. React State Management yazımızda diğer state yönetim yaklaşımlarıyla karşılaştırmasını bulabilirsiniz.
useReducer vs useState
useState, basit ve bağımsız state'ler için idealdir. Ancak state mantığı karmaşıklaştıkça kod kalabalığı ve hata riski artar. useReducer, bu durumda daha temiz bir alternatiftir. Aşağıdaki tabloda farkı görebilirsiniz:
| Özellik | useState | useReducer |
|---|---|---|
| Kullanım alanı | Basit, bağımsız state | Karmaşık, bağımlı state |
| Kod yapısı | Dağınık olabilir | Merkezi, düzenli |
| Test edilebilirlik | Düşük | Yüksek (reducer saf fonksiyon) |
| Performans | Her güncellemede yeniden render | Optimizasyon için uygun |
Temel Kullanım
useReducer hook'u şu şekilde kullanılır:
const [state, dispatch] = useReducer(reducer, initialState);
reducer fonksiyonu, mevcut state ve bir action alır; yeni state döndürür. dispatch ise action'ları göndermek için kullanılır. Örneğin, bir sayaç:
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
);
}
Pratik İpuçları ve Kontrol Listesi
Aşağıdaki kontrol listesi, useReducer'ı daha verimli kullanmanıza yardımcı olacaktır:
- Reducer'ı saf fonksiyon olarak yazın: Dışarıdan yan etki almayan, aynı girdiyle aynı çıktıyı veren fonksiyonlar oluşturun. Bu, test edilebilirliği artırır.
- Action tiplerini sabit olarak tanımlayın: Hataları önlemek için action tiplerini (örn.
INCREMENT) string sabitler veya enum kullanarak belirleyin. - Payload yapısını standartlaştırın: Action içinde
payloadalanı kullanarak veri taşıyın. Örn:{ type: 'SET_USER', payload: { id: 1, name: 'Ali' } }. - Karmaşık state için initial state'i ayrı bir dosyada tutun: Büyük projelerde initial state'i modüler hale getirin.
- Context ile birleştirin: useReducer'ı Context ile kullanarak global state yönetimi sağlayabilirsiniz. İlgili yazımızda bu yöntemi detaylıca inceledik.
- Async işlemler için middleware kullanın: Redux Thunk benzeri bir yapı için custom hook veya useEffect ile dispatch kombinasyonu kullanabilirsiniz. Async işlemlerde hata yönetimi için JavaScript Promise yazımıza göz atın.
- Performans için useMemo ve useCallback kullanın: Özellikle büyük state'lerde gereksiz yeniden render'ları önlemek için dispatch fonksiyonunu memoize edin.
- Reducer'ı test edin: Reducer saf fonksiyon olduğu için birim testleri kolaydır. Her action tipi için farklı durumları test edin.
Sık Yapılan Hatalar
useReducer kullanırken karşılaşılan yaygın hatalar ve çözümleri:
- State'i mutate etmek: Reducer içinde state'i doğrudan değiştirmeyin; her zaman yeni bir obje döndürün.
- Action tipini yanlış yazmak: String sabitleri kullanarak bu hatayı minimize edin.
- Gereksiz yere useReducer kullanmak: Basit bir sayacı useReducer ile yönetmek aşırı mühendislik olabilir. İhtiyaca göre seçim yapın.
- dispatch'i async fonksiyon içinde kullanırken dikkat: Event handler içinde dispatch çağrısı yaparken async/await kullanımı genelde sorunsuzdur, ancak reducer'ın saf kalmasına özen gösterin.
useReducer, doğru kullanıldığında React uygulamalarınızın state yönetimini hem daha güvenilir hem de daha okunabilir kılar. Karmaşık formlar, sihirbazlar veya oyun mantığı gibi senaryolarda bu hook'u tercih edebilirsiniz. Daha fazla performans ipucu için lazy loading yazımıza ve Web Workers makalemize göz atabilirsiniz.
Sık Sorulan Sorular
useReducer ne zaman kullanılmalı?
State birden fazla alt değer içeriyorsa, güncellemeler birbirine bağlıysa veya state mantığı karmaşıksa useReducer kullanılmalıdır. Basit ve bağımsız state'ler için useState yeterlidir.
useReducer ile Context kullanılabilir mi?
Evet, useReducer'ı Context ile birleştirerek global state yönetimi sağlayabilirsiniz. Bu yöntem, özellikle orta ölçekli uygulamalarda Redux'a alternatif olarak tercih edilir.
useReducer performansı etkiler mi?
useReducer tek başına performans sorunu yaratmaz. Ancak büyük state'lerde gereksiz yeniden render'ları önlemek için useMemo ve useCallback ile optimizasyon yapılmalıdır. Ayrıca reducer fonksiyonunun saf olması performansı olumlu etkiler.
useReducer ile async işlemler nasıl yapılır?
Reducer saf fonksiyon olduğu için async işlemler doğrudan reducer içinde yapılmamalıdır. Bunun yerine useEffect veya custom hook içinde async işlemleri yapıp dispatch ile sonuçları reducer'a iletebilirsiniz.
useReducer ve useState arasındaki temel fark nedir?
useState, her state güncellemesi için ayrı bir setter fonksiyonu sağlarken, useReducer bir reducer fonksiyonu ve dispatch mekanizması ile merkezi bir yapı sunar. useReducer karmaşık state'lerde daha düzenli ve test edilebilir bir çözümdür.






