combineReducer, Provider, connect … Redux Nasıl Kullanılır? #Bölüm-2

İlk bölümde genel hatlarıyla redux’un mantığını işlemeye ve çalışma prensiplerini anlatmaya çalıştık. Şimdi biraz daha ayrıntılı olarak işleyeceğiz. Önceki yazıda tek bir reducer’imiz ve bu reducer’a müdahalede bulunan tek bir action söz konusuydu. Gerçek uygulamalarda reducer sayısının birden fazla görülmesi mümkündür. Birden fazla reducer olması durumunda, işi kotarabilmemiz için kullanmamız gereken metot; “combineReducers” metodu olacatır.

Bir önceki anlatımdan devam ediyoruz. Öncelikle combineReducers’i index.js dosyamıza import etmemiz gerekiyor.

import { combineReducers, createStore } from 'redux';

Import ettikten sonra hali hazırda varolan foodReducer fonksiyonuna bir ikincisi olan drinkReducer ekleyelim.

function drinkReducer(state = 'coffee', action) {
return state;
}

Buradaki mantıkta bir değişme yok. İlk anlatımda olduğu gibi herhangi bir action’le iletişimde olmayan static bir reducer oluşturduk. Şimdi söz konusu iki reducer’dan bir grup yaratmadan önce drinkReducer’a ait action’i da oluşturalım.

const updateDrinkDatas = {
type: "UPDATE_DRINK",
payload: "cay"
}

Şimdi action’dan gelecek olan payload’i, eğer ki action type’i “UPDATE_DRINK” ise reducer’a gönderelim. Hemen yukarıda oluşturduğumuz drinkReducer fonksiyonunu şu şekilde güncelliyoruz.

function drinkReducer(state = 'kahve', action) {
switch (action.type) {
case "UPDATE_DRINK":
return action.payload;
default:
return state;
}
}

Bu tıpkı foodReducer’da yaptığımız işlem gibi. Şu an elimizde iki adet reducer ve iki adet action var. Yapmamız gereken reducer’ları combineReducers ile birleştirip store’a eklemek.

const reducers = combineReducers({
foods: foodReducer,
drinks: drinkReducer
})

Artık reducers adında yeni bir verimiz var. Store’a göndermemiz gereken de bu.

const store = createStore(reducers);

Şimdi console ile store’dan gelen veriye baktığımızda, bir obje içerisinde foods ve drinks adında iki property’nin döndüğünü göreceğiz. Değerleri de default değerleri olan “elma” ve “kahve” değerleri olacaktır.

Peşpeşe iki kere iki farklı action’i dispatch ettiğimizde iki reducer’in store’daki değerleri güncellediğini göreceğiz.

store.dispatch(updateFoodDatas);
console.log(store.getState());
store.dispatch(updateDrinkDatas);
console.log(store.getState());

Tekrardan console çıktısına baktığımızda, önce foodReducer’dan gelen state’in, sonrada drinkReducer’dan gelen state’in güncellenip store’a eklendiğini göreceğiz.

Uygulama içerisinde index.js dışında kalan diğer component’larda da store verilerini kullanmamız gerekecektir. Bunun için öncelikle uygulamamızı render ettiğimiz noktada, Provider’i kullanmalıyız.

En temel anlatımıyla Provider, uygulamamız içerisinde store objemizi etkinleştirmeye yarar. Böylelikle kullanacağımız tüm container ve component’larda redux’la birlikte gelen store verilerini kullanabilir ve action’larla müdahalede bulunabiliriz.

Provider’i index.js’e dahil ediyoruz.

import { Provider } from 'react-redux';

Daha sonrasında App’i render ederken Provider taşıyıcısına sokuyoruz. Burada Provider’a yarattığımız store’i parametre olarak vermemiz gerekiyor.

ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
registerServiceWorker();

Bu aşamadan sonra, App component’ina geçmeliyiz. App.js içerisinde içerisinde connect ve mapStateToProps’u kullanarak store objesini props olarak kullanabileceğiz. Bu store’a App içerisinden erişip istediğimiz veriyi güncelleyip, varolan verileri de kullanabilmemiz anlamına geliyor.

create-react-app ile birlikte gelen App.js içerisindeki bazı şeyleri temizleyelim ki, daha anlaşılır bir yapı kurabilelim(return içerisinde dönen düm sanal dom öğelerini kaldırıyoruz. Ben store’a action ile erişebilmemiz için sadece button ekliyorum. Ayrıca handleFoodUpdate adında bir fonksiyon ve o fonksiyonun içinde de updateDrinkDatas isminde bir action yaratıyoruz). Tüm bunları yaptıktan sonra yapmamız gereken tek şey kalıyor. “this.props” ile birlikte dönen store objesinin dispatch metodunu kullanarak updateDrinkDatas action’unu reducer’a göndermek ve state’i güncellemek.

Bu aşamada anlatımı çok fazla parçalamadım. App.js ve index.js’in görünümü şu şekilde olmalıdır.

App.js görünümü:

import React, { Component } from 'react';
import './App.css';
import { connect } from 'react-redux';
class App extends Component {
constructor(props) {
super(props)
this.state = {}
this.hanldeFoodUpdate = this.hanldeFoodUpdate.bind(this);
}
hanldeFoodUpdate() {
const updateDrinkDatas = (item) => {
return {
type: "UPDATE_FOOD",
payload: item
}
}

this.props.dispatch(updateDrinkDatas('gazoz'));
}
render() {
return (
<div className="App">
<button onClick={this.hanldeFoodUpdate}>Run Action</button>
</div>
);
}
}
const mapStateToProps = state => {
return state
}
export default connect(mapStateToProps)(App);

index.js görünümü:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { combineReducers, createStore } from 'redux';
import { Provider } from 'react-redux';
function foodReducer(state = 'elma', action) {
switch (action.type) {
case "UPDATE_FOOD":
return action.payload;
default:
return state;
}
}
function drinkReducer(state = 'kahve', action) {
switch (action.type) {
case "UPDATE_DRINK":
return action.payload;
default:
return state;
}
}
const reducers = combineReducers({
foods: foodReducer,
drinks: drinkReducer
})
const store = createStore(reducers);
const updateFoodDatas = {
type: "UPDATE_FOOD",
payload: "armut"
}
store.dispatch(updateFoodDatas);
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
registerServiceWorker();

Yukarıda mapStateToProps ile işlediğimiz state, Provider’dan gelen store objesini connect kullanarak App’e yerleştirmemizi sağlıyor. Yarattığımız handleFoodUpdate fonksiyonu butona tıkladığımızda tetikleniyor. Sonrasında ise drink state’inin gazoz olarak güncellendiğini görüyoruz.

Redux kendi içerisinde çok karmaşık bir yapı da olabiliyor çok basite de indirgenebiliyor. Burada önemli olan temel kavramlarını ve mantığını olabildiğince özümsemek. Sonrasında içinde bulunduğunuz projenin ihtiyaçlarına göre derinlerine inebilme imkanınız doğacaktır.

Anlatımı gözden geçirerek gerekli yerlerde düzeltmelerde bulunan Tahsin Cem Yılmaz’a çok teşekkürler.