React’ta redux ile middleware kullanımı ve redux-thunk

Ali Yıldızöz
SDTR
Published in
5 min readJun 28, 2020

Merhabalar,

Bu yazımda Redux’a nasıl middleware eklenir , neden ihtiyaç vardır, redux-thunk ile api çağrılarımızı nasıl yaparız vb. sorulara cevaplamaya çalışacağım. Redux’ı veya React’ta redux’ın kullanımı ile ilgili anlamadığınız bir nokta varsa önceki yazılarıma göz atmanızı öneririm.

Middleware’e neden ihtiyacımız var ?

Redux’ta bir kuralımız var. Reducer’larımız pure olmalı ve asla side effect yaratacak işlemleri barındırmamalıdır. Bazı durumlarda -hatta çoğu durumda- pure olmayan işlemler yapmak zorunda kalırız. Bu işlemler ; api istekleri, bazı javascript fonksiyonları(math.random, array.push) veya kendi uygulamamızın gerektirdikleri olabilir. İşte tam bu noktada middleware ihtiyacı ortaya çıkıyor. Tabii, bu middleware’ler sadece side effect işlemleri için yoklar. Aynı zamanda state’timizi takip etmek için bazı ekstra araçları da middleware olarak kullanabiliriz.

Bu yazımda 2 tane middleware’den bahsedeceğim.

redux-thunk middleware

Reducer’ın pure kalmasını sağlayan bir kütüphanedir. Side effect işlemlerini bu kütüphaneyi kullanarak yaparız. Çok basit bir işlem yapar. Normalde biz, dispatch kullanarak action’ı reducer’a parametre geçip state’i değiştirirdik. Bu kütüphane ile dispatch fonksiyonuna , action -yani obje - değilde yapacağımız işlemlerin olduğu bir fonksiyon göndeririz. Bu sırada thunk middleware’imiz, gelen parametrenin fonksiyon olup olmadığını kontrol edip fonksiyon ise çalıştırıyor. Fonksiyon içinde dispatch’e tekrar bir action gönderiliyor. Yine aynı şekilde thunk middleware araya girip dispatch’e gönderilen action’ın fonksiyon olup olmadığına bakıyor, eğer fonksiyonsa yine çalıştırıyor.Bu şekilde ,ta ki bir action -obje- yakalayana kadar devam eder. Objeyi yakaladığı an ,reducer’a bu objeyi yani action’ı parametre gönderiyor. Biraz karışık oldu biliyorum. Aşağıda ki flow üzerinden adımları tek tek anlatacağım.

redux-thunk data flow
  1. Dispatch fonksiyonuna action parametre olarak geçirilir.(action’ın bir fonksiyon olduğunu düşünelim.)
  2. Thunk middleware araya girerek, action’ın fonksiyon olup olmadığına bakıyor.
  3. Action’ımız fonksiyon olduğu için bu fonksiyona dispatch parametre gönderilip ,fonksiyonumuz, middleware içinde çalıştırılıyor. Fonksiyonumuz , api çağrısını veya ne işlem yapıyorsa o işlemi yapıp bir action-obje- yaratıyor. Parametre olarak gelen dispatch’e de ,yaratılan action parametre verip tekrar çalıştırıyor.
  4. Dispatch tekrar çalıştırıldığı için thunk middleware’miz tekrar araya giriyor. Ve bu işlemler yine tekrarlanıyor.
  5. Gelen action artık bir obje olduğu için normal yoluna devam ediyor. Yani reducer’a parametre geçiliyor.
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}

return next(action);
};
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

Yukarıdaki kısacık fonksiyon tüm işlemlerimizi yapıyor. Gelen action’ın tipine bakıp fonksiyon ise gerekli parametreleri verip çalıştırıyor, değilse sonraki adıma geçiyor. Fonksiyon olarak gönderdiğimiz action’a, dispatch ve yukarıdaki diğer değerler parametre gönderiliyor.

Fonksiyonumuz dispatch’i kullanmak zorundadır. Aksi halde programımız ilerlemez.

Nasıl Kullanılır ?

Projemize dahil etmek için aşağıdaki komutu çalıştırıyoruz.

npm install redux-thunk

Aşağıda middleware’lerimizi eklemek için redux’ın applyMiddleware fonksiyonundan yararlanıyoruz. createStore fonksiyonunun ikinci parametresine bu fonksiyonu göndererek middleware’lerimizi aktif hale getiriyoruz.

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';

const store = createStore(rootReducer, applyMiddleware(thunk));

Örnek

Önceki yazımda,redux’ın react ile kullanımıyla ilgili bir örnek yapmıştım. Redux-thunk’ı da bu örnek üzerinde kullanacağım.

Örneğimiz’de todo’ların başlangıç değerlerini api den çekeceğiz. Bunun için gerçek bir uygulama yapamayacağımızdan, sahte bir api kullanacağız. Böyle durumlarda ve uygulamalarımızı denemek için geliştirilen bir kütüphane var json-server. Bizde bu kütüphaneyi kullanacağız.

json-server kurulumu

npm install -g json-server

Yukarıdaki komutu çalıştırarak bilgisayarımıza kuruyoruz.

Bu işlemden sonra api’den çekeceğimiz verileri db adında bir json dosyasına yazıyoruz.

db.json

{
"todos": [
{"todo": "todos1"},
{"todo": "todos2"},
{"todo": "todos3"}
]
}

db.json dosyamız nerede ise oranın path’ini yazarak aşağıdaki komutu çalıştırıyoruz.

json-server --watch db.json

dosyamız, proje klasörümüzün içinde ise bir yol belirtmemize gerek yok. Başka bir yerde ise dosyanın tam yolunu vererek komutu çalıştırmalıyız. Bu işlemlerden sonra todolarımız “localhost:3000/todos” endpoint’inde görüntülenecektir. Başka endpoint’lerde ekleyebiliriz. Bu kütüphanenin bir çok özelliği vardır incelemek için github adresine gidebilirsiniz.

Redux-thunk’ın kurulumunu yaptığınızı varsayıyorum.Yapmadıysanız yukarıda nasıl yapıldığını anlattım.

Bu state için öncelikle ,yeni bir action ve reducer’a yeni bir case eklemeliyiz.

src/redux/actions/actionTypes.js

src/redux/reducers/todoReducer.js

src/redux/actions/thunkActions.js

Api isteği yapan fonksiyonlarımızı tutacak bir dosya oluşturuyoruz. Direkt actionCreators.js dosyamıza da ekleyebiliriz ama daha modüler ve uygulama daha kompleks hale gelmesin diye ayrı bir dosyada yapmak daha mantıklıdır. Ben burada daha genel bir dosya oluşturdum ama çoğu gerçek hayat projelerinde, yaptığı işlemlere göre bu fonksiyonlar gruplandırılıp ayrı dosyalarda tutulur.

İsteğimizi yaptıktan sonra ,gelen datayı kullanarak bir action oluşturup dispatch metoduna parametre geçiyoruz. Bu işlemden de sonra, thunk middleware tekrar devreye girerek ,gelen action’ı kontrol edip obje ise reducer’a parametre geçiyor.

Bu fonksiyonu TodoSearch Component’inde kullanacağız. Component, ilk render işleminde bu verileri default olarak gösterecek. İlk render işleminde çalışacak fonksiyonu(getTodosApiRequest) ,react'ın lifecycle metotlarından olan componentDidMount fonksiyonunu kullanarak kullanacağız.

src/components/TodoSearch.js

mapDispatchToProps fonksiyonunda component ilk render olduğunda tetiklenecek action’ı tanımladık. Action’ın olduğu dosyayı component’imizde import etmeyi unutmamalıyız(5.satırda). Action’ı ,Component ilk render işleminden hemen önce çalıştırmak için componentDidMount fonksiyonundan faydalanıyoruz(12.satırda). Bu sayede uygulamamız ilk açıldığında, api’den gelen 3 tane todo’yu -db.json dosyasında bu kadar verdik.- default olarak gösterecek.

Uygulamamız ilk açıldığındaki ekran görüntüsü.

redux-logger middleware

State her değiştiğinde; hangi action’ın çalıştığı, önceki state’in ve değiştikten sonraki state’in son halini konsola yazar. Bu sayede kullanıcının ne yaptığı an an takip edilebilir.

Nasıl Kullanılır ?

Projemize dahil etmek için aşağıdaki komutu çalıştırıyoruz.

npm i --save redux-logger

Yine aynı şekilde applyMiddleware fonksiyonu ile logger midleware’mizi createStore fonksiyonuna parametre geçiyoruz.

import { applyMiddleware, createStore } from 'redux';
import logger from 'redux-logger'
import rootReducer from './reducers/index';
const store = createStore(rootReducer,applyMiddleware(logger))
Uygulamamız ilk açıldığında ,gerçekleşen api isteği sonucu react-logger middleware’nin çalışması.

Örneğe buradan ulaşabilirsiniz.

Redux ile ilgili yazılarımın sonuna geldik. Umarım faydalı olmuştur. Görüşmek üzere.

--

--