useReducer ile State Yönetimi
Giriş
useReducer, React'ın state yönetimi için yerel olarak sunduğu iki temel hook'tan biridir. State yönetimi için kullanılan diğer hook olan useState ile çok benzer bir kullanıma sahiptir ve onun gelişmiş bir versiyonu olarak da düşünülebilir.
Reducer ismi, bir array fonksiyonu olan reduce()’den gelir ve kelime anlamı indirgemektir. Birden çok fonksiyonu tek bir fonksiyona indirgeyerek tek bir değer döndürmeyi sağlar.
useReducer ve useState benzer görevleri gerçekleştirmek için kullanılabilir. Ancak, useReducer, yapılacak işlemleri ön tanımlı olarak tek bir fonksiyonda izole etmemize izin verir. Bu sayede; hata ayıklama, okunabilirlik ve güncelleme konularında kolaylık sağlar. Ayrıca, reducer fonksiyonları ayrı bir dosyada tutularak bileşen ve mantığın ayrıştırılması mümkün olur.
useReducer Yapısı
Aşağıdaki örnekte basit bir sayaç uygulaması ile useReducer kullanımı gösterilmektedir. Her bir bölümü ayrı ayrı incelemeden önce bütüne göz gezdirmeniz faydalı olacaktır.
useReducer’ın Başlatılması
İlk olarak useReducer’ın React’dan içe aktarılması ve aşağıdaki görseldeki gibi başlatılması gerekmektedir. Yorum satırına alınmış useState örneği ile karşılaştırarak inceleyecek olursak;
- İkisi de 2 elemanlı bir array döndürür ve destructuring işlemi ile ayrıştırılabilir.
- İkisinin de ilk elemanı state değerini tutar. İkinci elemanı ise state’i değiştirmek için kullanılan bir fonksiyondur.
- setState() ile mevcut state doğrudan değiştirilir, dispatch() ise counterReducer fonksiyonunu tetikleyerek state’i değiştirir.
- useState hook’u parametre olarak bir başlangıç değeri alır (initialState). useReducer ise kendi tanımladığımız bir reducer fonksiyonu ile birlikte bir başlangıç değeri alır (useReducer’ın üçüncü ve opsiyonel parametresine daha sonra değineceğiz).
Başlangıç Değeri
useReducer’ın ikinci parametresi olan initialState ile state’in ilk durumdaki değeri belirlenir. Bu başlangıç değeri genellikle bir array veya obje olur. Bunun sebebi useReducer ile genellikle birden çok işlemin bulunduğu state yönetimi işlemlerinin yapılmasıdır. Ancak ilkel veri türleri de kullanılabilir. Ayrıca initialState değeri verilmediği durumlarda, başlangıç değeri undefined olur.
Reducer Fonksiyonu ve Dispatch
Yine aşağıdaki örnek üzerinden reducer fonksiyonunu inceleyecek olursak;
- Reducer fonksiyonları dispatch() ile tetiklenir ve bir obje parametre olarak gönderilir. Gönderilen bu değere reducer fonksiyonunun action parametresi üzerinden erişilir.
- Action objesi type ve payload değerini tutar. Type değeri, çalıştırılacak işlemi belirlemek için kullanılan bir isimdir. Payload ise çalıştırılacak işleme gönderilen parametredir ve zorunlu değildir.
- Reducer fonksiyonu iki parametre alır. Birinci parametre mevcut state değerini tutar, ikinci parametre ise action.type ve action.payload değerlerini tutar. action.type değerine göre yönlendirilecek işlem bir switch case yapısı ile veya if else blokları ile belirlenebilir.
- Reducer fonksiyonunun aldığı parametreler, destruct edilerek şu şekilde de kullanılabilir: ({ count }, { type, payload }).
- Reducer fonksiyonu yeni state değerini döndürür ve bu yüzden her koşullu ifade yeni bir değer return etmelidir. else bloğunda veya default bloğunda type değerinin hiç bir koşulu sağlamadığı durumda döndürülecek değer olarak bu örnekte mevcut state kullanılmıştır. Ancak bu genellikle istenen bir durum değildir ve tespit edilmesi zor görünmez hatalara sebep olabilir. Bu yüzden örnekteki yorum satırında tanımlandığı gibi bir hata döndürülmesi daha doğru olur.
Üçüncü Parametre: init
Yukarıdaki örneklerde useReducer’ın iki parametre ile başlatılmasını gördük. Ancak useReducer’ın isteğe bağlı bir parametresi daha var. init isimli bu parametre, başlangıç değeri belirlenirken işlem yapılması gerektiğinde faydalıdır. Aşağıdaki örnekteki gibi maliyetli bir fonksiyon sonrasında başlangıç değerini belirleyeceksek, üçüncü parametre kullanılmalıdır.
Örnekteki yorum satırında olduğu gibi bu fonksiyona doğrudan değer göndermiş olsaydık her render işleminde fonksiyon tekrar çalıştırılacaktı. Ancak init fonksiyonu ile yapılan örnekte bu işlem sadece bir defa yapılır. Sonuç olarak her iki örnek de aynı işlemi yapar ve üç parametreli örnek daha optimizedir.
Bonus
- Immer kütüphanesi, React’ın resmi sitesinde önerilen ve reducer yazmayı kolaylaştıran bir kütüphanedir.
- Reducer fonksiyonları aşağıdaki gibi bir dosya yapısı ile bileşenlerden ayrı tutulabilir.
- useReducer’ın array değerlerle birlikte kullanımına örnek bir todo uygulaması;
Tüm yazılarımın kategorize edilmiş bir listesine aşağıdaki linkten erişebilirsiniz.
https://github.com/oguzhanuyanik-sr/articles