REDUX

Redux-Thunk vs Redux-Saga

Onur Dayıbaşı
Frontend Development With JS
6 min readJan 23, 2021

--

Bu yazımda daha önce Flux Mimari konusunda yazdığım bazı konuları tekrar ederek başlayacağım. İsteyen önceki yazıyı buradan okuyabilir.

Flux Mimari Bu şekildeydi

Store içerisinde State tutan Reducer bulunurken. Bu Reducer topluluğu Async işlemler olduğunda Side Effect açık bir hale geldiğinden bahsetmiştik. Bu da sistemin stabil çalışmasını engelleyecek bir durum.

Pure Function: Bizim bir fonksiyon ne kadar çağrım yaparsak yapalım. Her zaman aynı parametreler için aynı sonucu veriyor ise bu tip fonksiyonlara denir.

Peki Pure Function olmasını Engelleyen Side Effect’ler neler ?

  • Fonksiyon içerisinde random() veya getTime() gibi değerler kullanılarak sonucun etkilenmesi
  • Fonksiyon içerisinde I/O işlemleri ve. sonucunda hataların oluşması , bekleme veya verinin yüklenmesi vb… (Backend sunucu ile konuşma, LocalStorage erişim vb…

Bu durumda Reducers nasıl Pure hale getirebiliriz ?. Bunun için Redux kendi bir takım middleware mekanizmalarına takılabilir halde yapmıştır. Middleware sadece SideEffect engellemek için değil başka başka amaçlar içinde Redux takılabilir.

Redux With Middleware

Ama bizim burada konumuz Reducer bu tür yan etkilerden korumak olduğu için burada genellikle kullanılan 2 tip middleware bulunur:

1. Redux-Thunk

Redux normal şartlarda sync çalışırken aşağıdaki sırası ile aşağıdaki adımları uygulayarak kullanırız.

  1. Action ile bir Command Objesi oluşturuyoruz ve biz bu komut objesini
  2. Biz bu obje Dispatcher ile Store iletiyoruz.
  3. Store Reducer tetikliyor.
  4. Reducer yazdığımız iç mantık doğrultusunda Reducer yeni bir state oluşturup bunu dönüyor
  5. Listeners tetiklenir ve Container → Component aracılığı ile ilgili bileşenler yeni state bilgileri ile tetiklenir.

Bu Sync kullanım için React Sanal DOM Ağacında, Uzak Bileşenleri Redux üzerinden Nasıl Konuştururuz ? bir yazı ve örnek yazmıştım. Adım 1 ve 2 Container içerisinde gerçekleşiyor. 4ncü adımda bizim yazdığımız Reducer içerisinde gerçekleşir. 5nci adımlarda bu state dinleyen Component’lar yeni state Container aracılığı ile erişip güncellemeleri gerçekleşir.

Peki her zaman Action nesnesi Objemi oluşturacak ? Action Async arka arkaya yapılacak işlemler olabilir veya aynı async fonksiyon birbirinin ardı ardına çağrılabilir bu tip durumlarda Object yerine bu işlemi soyutlayan bir fonksiyon dönmesi daha mantıklı olabilir. Bu durumu biraz daha anlaşılır olması için örnekler ile anlatalım.

Stack Overflow: Dispatching Redux Actions with a Timeout Dan Abramov explains the basics of managing async behavior in Redux, walking through a progressive series of approaches (inline async calls, async action creators, thunk middleware).

Yukarıdaki örneğe göre Notification Mesajı gösterme ile ilgili bir örnek var Aşağıdaki resimde Action ile oluşturduğumuz Command Obj görebilirsiniz. Bu komut objelerini Store ilettiğimizde Reducer kendi state Göster/Gizle olarak güncelleyecektir.

Show/Hide Notification Action

Peki biz bu Notification gösterildikten 5 saniye sonra kapatılmasını istersek aşağıdaki şekilde bir kod yazmamız gerekiyor. Bu kod Action Object olabilmesi için Component/Container yapısında aşağıdaki kodun olması gerekiyor.

Timeout Logic

Bu durumun 2 dezavantajı bulunmaktadır.

  • Bileşenlerin Timeout Logic bilmesi , bu konunun geçtiği her bileşende bu kodun duplicate etmesi anlamına gelecektir. .
  • Eğer burada bir ID mekanizması olmassa 2,3 bileşenden arka arkaya gelen notification gösterme birbirine karışabilir ve 1 bileşenin gizleme fonksiyonu 2 bileşenin isteğinin gizlenmesini neden olur.

Bunun 2 problemin çözümü 1ncisi için ortak bir util fonksiyon oluşturup action öncesinde bunu çağıracak parametreleri geçmek, 2ncisi de ID mekanizmasi ile Notification işlemlerinin birbiri ile çakışmasını engellemek.

showNotificationWithTimeout ve ID

Bu yöntem Singleton bir yapıda olduğu için çok tercih edilen bir yöntem olmaz. Özellikle ServerSide Rendering sırasında her bir istek için store farklılaşarak çalışacak ve test işlemleri zorlaşacaktır.

Redux-Thunk aslında 14 satırlık bir kod.

Redux Thunk Middleware Kodu

Yukarıdaki kodun yaptığı ise dispatch ve getState parametrelerini işleyerek kendisine verilen action eğer fonksiyon ise çalıştırmak değil ise bir sonraki action çalışmasına ve object olarak store reducer tetiklenmesini sağlar. Yani Action obje mi dönüyor yoksa Fonksiyon mu ? bu doğrultuda kodu işleten bir yapı oluşturuyor.

Aşağıdaki örnekte asyn olarak bir API üzerinden foo bilgisi çağırma işlemi var ama biz foo objesini uzak makineden çağırdığımızda henüz user bilgisi elimizde hazır değil bu durumda bizim bir Fonksiyon Zinciri oluşturup bunu thunk mekanizmasına vermemiz gerekiyor. Thunk yapısı bu zinciri arka arkaya çalıştırıp duruma göre’da Store güncellemelerini yapması gerekiyor .

Foo Async

Bu durumu biraz görselleştirirsek aşağıdaki gibi foo çağrımı sırasında Action dönen nesne yerine bir function (callback/promise) zinciri dönecek ve bu zincir çağrımları sonucunda istediğimiz objeye erişmiş olacağız. Bu adımları Redux-Thunk Middleware işleme kısmını görselleştirirsek Bu sayede bizim Action dönen nesne ister Obj/Fonksiyon olsun her durumda da Store ObjCommand gönderilebilir halde soyutlamış olduk.

Redux-Thunk Middleware

Thunk Nedir?

Thunk bir tanımın gecikmeli olarak çağrılmasını sağlamak için bir fonksiyon ile çevrelenmesidir. Aşağıdaki örnekte x =3 ama foo fonksiyonu ile bu işlemi hesaplanmasını geciktirebiliriz taki o fonksiyon çağrılana kadar. Thunk bu soyutlama ve geciktirme işlemini gerçekleştiriyor.

https://github.com/reduxjs/redux-thunk

2. Redux-Saga

Bazı uygulamalarda Async Kontrol Akış gereksinimleri çok daha kompleks ve thunk yapısı ile tanımlanması zor olabilir. Örneğin;

  • Başarısız istekleri yeniden denemek
  • Token ile yeniden authanticate olmak
  • Hata durumunda işlemleri geri alma (Saga Pattern yazımı okuyabilirsiniz)

Bu durumda Async daha detaylı kontrol etmek için JS Generator altyapısını kullanan Redux Saga tercih edilebilir.

It uses an ES6 feature called Generators to make those asynchronous flows easy to read, write and test. (if you’re not familiar with them here are some introductory links) By doing so, these asynchronous flows look like your standard synchronous JavaScript code. (kind of like async/await, but generators have a few more awesome features we need)

You might’ve used redux-thunk before to handle your data fetching. Contrary to redux thunk, you don't end up in callback hell, you can test your asynchronous flows easily and your actions stay pure. (https://redux-saga.js.org/)

Not: Generator Fonksiyonların nasıl çalıştığını öğrenmek için daha önceden yazmış olduğumuz bu yazıyı okumanızı öneririm

Saga’nın içerisinde bir takım Helper yapıları ile bizim belli kalıptaki Async işlemlerimiz kolay bir şekilde yapmamızı sağlar.

Component Dispatch benzer şekilde çağrılır. Mesele hangi middleware uyguladığınız ile ilgili.

Component Dispatch (https://redux-saga.js.org/)

Saga.js tarafında USER_FETCH_REQUEST isteğine register olmuş SAGA yapımız, bileşen/container gelen bu istek objesini ele alarak generator yapısı ile bunu işletmeye başlar.

Saga (https://redux-saga.js.org/)

Yukarıdaki örnekte Fetch işlemini nasıl ele alacağınız konusunu Saga Helpers faydalanarak yönetebilirsiniz.

takeEvery : Bizim sunucudan AJAX yöntemi ile request yapıp veri çağırmamızı sağlar. takeEvery aynı zamanda yapılan her request kabul eder.

takeEvery from https://redux-saga.js.org/docs/basics/UsingSagaHelpers.html

takeLatest: Aynı anda sunucundan bir tane Fetch request yapılmasını sağlar.

takeLatest https://redux-saga.js.org/docs/basics/UsingSagaHelpers.html

Aynı zamanda Declarative Effects olan call ve put faydalanarak Generator yield direk kullanmak yerine bu çağrımlarda bir fonksiyon ile wrap edilir.

call ve put https://redux-saga.js.org/docs/basics/DeclarativeEffects.html

Geri kalan Saga MiddleWare Store entegre etmek

Saga (https://redux-saga.js.org/)

Not:

Özetle basit bir arka arkaya Promise çağırımı var ise Redux-Thunk, ama karmaşık state lerin yönetilmesinin gerektiği yapılarda Generator yield destekli Redux-Saga tercih edilmeli. Konuyu ilerleyen zamanda ki yazılarda daha da derinleştirerek anlatmaya çalışacağım.

Referanslar

Okumaya Devam Et 😃

Bu yazının devamı veya yazı grubundaki diğer yazılara(JS Async Programlama) erişmek için bu linke tıklayabilirsiniz.

Bu yazının devamı veya yazı grubundaki diğer yazılara(React Redux) erişmek için bu linke tıklayabilirsiniz.

--

--