React’ta redux nasıl kullanılır ?

Ali Yıldızöz
SDTR
Published in
6 min readJun 24, 2020

Merhaba Arkadaşlar,

Önceki yazımda redux’ın ne olduğunu,çalışma mantığını anlatmaya çalıştım. O yazıma buradan ulaşabilirsiniz.

Bu yazımda ise react’a redux’ı nasıl kullanacağız, neden ihtiyacımız var vb. soruları cevaplamaya çalışacağım.

React’a redux’a neden ihtiyacımız var ?

React’ta component’ler sürekli bir biri ile etkileşim içindedir. Bunun nedeni bir birinin state’ini kullanmalarıdır. Örneğin bir sayfanın navbar’ında login olan kişinin ismini gösteriyoruz. Bu isim, navbar component’inin state’dir. Daha sonra kişinin profil sayfasına gittiğimizde orada da ismini görürüz. Bu ismi öğrenmek için, her seferinde servisimize istek atmak çok kullanışlı olmayacağından, bu isim bilgisini tutan component’ten bilgiyi almak ,daha hızlı ve efektif olacaktır. Bu olaya component drilling adı verilir.

State değiştikten sonra component’lerin kendini güncellemesi.

Bu durum bir kaç sorunu beraberinde getiriyor. Bunlardan ilki bir component’in durum bilgisine ihtiyaç varsa bu bilgi her zaman üst katmandan gelmek zorundadır. Bu durumda bu bilgi için her zaman üst katmanlara bağımlı olacağız. İkincisi ise , component sayıları arttıkça paralel olan component’ler bir birinin state’ine ihtiyaç duyduğu zaman ; state’i, bir birine direkt göndermeyecekleri için bu durum ikisininde atası olan bir component’te state‘i tutmaya itecektir. Her zaman state’i merkezileştirme gibi bir yapıya gidilecektir.

Redux’ın buna sağladığı çok basit bir çözümü vardır. State’leri store adında bir yapıda tutar. Tüm component’ler bu store’ bağlıdır. Bir component ,state ile ilgili bir işlem yaparsa ,store’un ilgili state’ine abone olan componen’tler otomatik kendini güncelliyor. Bu sayede tüm component’ler tek bir yapıyla muhatap olduğu için daha yönetilebilir bir state oluyor.

Bir component’in store güncellemesi sonucu etkilenen componentler.

Nasıl kullanılır ?

Öncelikle iki tane kütüphaneye ihtiyacımız var redux ve react-redux.

Bunları indirmek için aşağıdaki komutları kullanıyoruz.

npm install redux
npm install react-redux
//tabii siz hangi paket yönetim aracını kullanıyorsanız ona göre indirin.

Reducer oluşturma.

Store’umuz tek bir state’i tutmayacağı için reducer’larımız da birden fazla olacaktır. Her bir reducer store’un ilgili state’i ile işlem yapacaktır.

Bu state’lere hem başlangıç değerlerini vermek hemde reducer’ların ilgileneceği state’i belirtmek için initialState.js adında bir dosya oluşturuyoruz.

örnek initialState dosyası

 export default {
categories:[],
currentCategory: {}
}

örnek reducer dosyası

import * as actionTypes from "../actions/actionTypes"
import initialState from "./initialState";
export default function changeCategoryReducer(state = initialState.currentCategory, action) { switch (action.type) {
case actionTypes.CHANGE_CATEGORY:
return action.payload
default:
return state;
}
}

Dikkat ederseniz reducer, initialState’tin sadece ilgili state’ini değiştiriyor.

Store oluşturma.

createStore fonksiyonunu kullanarak store’umuzu oluşturuyoruz.

import { createStore } from "redux";
import reducer from "./reducer";
const store = createStore(reducer);

Reducer’larımız birden fazla ise redux’ın combineReducers fonksiyonunu kullanabiliriz.

import { createStore,combineReducers } from "redux";
import reducer1 from "./reducer1";
import reducer2 from "./reducer2";
const reducers = combineReducers({
reducer1,
reducer2
});
const store = createStore(reducers);

createStore fonksiyonu geriye bir obje dönüyor.

  • dispatch: reducer’ı tetikleyen fonksiyon. Bu fonksiyonu doğrudan kullanmayız. Bu işlemi react-redux kütüphanesi ile gerçekleştiririz.
  • getState: mevcut state’ti dönen fonksyion. Spesifik olarak bir state dönmez. Reducer’da kullanılan state’leri döner.
  • replaceReducer: adından da anlaşılacağı gibi mevcut reducer’ları, parametre olarak geçilen reducer’larla değiştirir. Örneğin aynı state üzerinde farklı işlemler yapan iki reducer’imiz varsa, bazı durumlarda bu iki reducer’i değiştirmek isteyebiliriz.
  • subscribe: component’leri bu fonksyion ile abone ederiz. Bu fonksiyonu da doğrudan kullanmayız. React-redux kütüphanesinin metotları ile bunu gerçekleştiririz.

Provider

Store’umuzu component’ler de kullanmak için bu nesne ile uygulamamızı sarmalıyoruz. Parametre olarak store’u veriyoruz.

import { Provider } from 'react-redux';
import { createStore,combineReducers } from "redux";
import reducer1 from "./reducer1";
import reducer2 from "./reducer2";
const reducers = combineReducers({
reducer1,
reducer2
});
const store = createStore(reducers);ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));

Connect

Component’leri state bağlayarak “this.props” üzerinden state ve action’lara erişim sağlamak için kullanılır.

import { connect } from "react-redux";
import { bindActionCreators } from 'redux'
import { action1 } from "../redux/actions"
class Component1 extends Component { render() {
return (
<div>
<h1>{this.props.state1}</h1>
<button onClick={this.props.action1}>click</button>
</div> )
}
}
function mapStateToProps(state) {
return { state1: state.reducer1
state2: state.reducer2
}
}
function mapDispatchToProps(dispatch) {
return {
action1: bindActionCreators(action1, dispatch)
//action1: ()=> dispatch(action1())
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Component1);

mapStateToProps: bu fonksiyon ile state’imize , direkt “this.props” üzerinden ulaşabiliyoruz. this.props.state1 bu fonksiyona parametre olarak gelen state üzerinden , erişmek istediğimiz state’i hangi reducer değiştiriyorsa onu kullanmalıyız. Örneğin reducer1 state1'i değiştirip geriye yeni bir state1 döndüğü için parametre olarak gelen state üzerinden reducer1'i çağırmalıyız state.reducer1.

mapDispatchToProps: dispatch’i props üzerinden tetiklemek için kullanılır.

bindActionCreators: bu fonksiyon , verilen parametrelere göre bir tetiklemeye hazır bir action yaratıyor. Yaptığı işlem buna eşdeğerdir. dispatch(action1())

Component’i bağlamak için en sonda component’i ,parametre olarak vermeliyi unutmamalıyız.

Örnek

Örnek olarak bir todo uygulaması yapacağız. Basit bir şekilde ekleme , silme ve arama işlemleri olacak.

Öncelikle aşağıdaki komut ile “redux-example” adında bir react projesi oluşturuyoruz. Sonrasında redux ve react-redux kütüphanelerini yüklüyoruz.

npx create-react-app redux-example
npm install redux
npm install react-redux

Uygulamamızın görünümü için reactstarp ve bootstrap kullanacağız. Bu kütüphanelerin yükleme komutları da aşağıdadır.

npm install --save bootstrap
npm install --save reactstrap react react-dom

Css’lerin etki etmesi için index.js dosyamıza bootstrap css dosyasını import etmemiz gerekir.

import 'bootstrap/dist/css/bootstrap.min.css';

Kütüphanelerimizi yükledikten sonra, src dosyamıza redux adında bir klasör oluşturuyoruz. Bu klasöre action’ larımız ile ilgili dosyalar koymak için actions , reducer’larımız için reducers adında iki klasör daha açıyoruz.

src/redux/actions/actionTypes.js

Bu dosyada todo’larımız üzerinde yapacağımız işlemlerin tiplerini belirliyoruz.

src/redux/actions/actionCreators.js

Action’ları tek tek üretmek zor ve mantıksız olacağından actionCreator’lardan faydalanırız. Verdiğimiz parametreye göre action’larımız hızlı bir şekilde üretecek.

src/redux/initialState.js

Reducer’a state’in,başlangıç değerlerini ve state tiplerini belirtmek için bu dosyaya gerekli bilgileri veriyoruz.

todos: Tüm todolarımızı tutatacak array .

filterTodos: todos üzerinde yaptığı arama sonuçlarını tutacak array. Bunu ayrı olarak yapmaktaki amaç; bir filtre işleminde todo’ları silmemek içindir.

src/redux/reducers/todoReducer.js

Gelen action tipine göre ekleme silme ve arama işlemlerini gerçekleştiriyoruz.

Dikkat ederseniz her zaman yeni bir obje dönüyorum. Mutlaka objenin referansını değiştirmek zorundayız.

  • TODO_ADD: eski state’ti bir array’e kopyalayıp(Object spread opretaor) gelen todo’yu kopyalanan array’e ekliyorum.
  • TODO_REMOVE: gelen todo hariç tüm todo’ları yeni bir array olarak dönüyorum.
  • TODO_SEARCH: yine “action.payload” tan gelen değere göre arama yapıp filtre sonucunu “state.filterTodos” a set ediyorum.

Tüm case’lerde initialStat’e uygun bir obje dönmek zorundayız.Eğer reducer’ımız başka bir state üzerinde çalışsaydı, ona uygun dönülecekti.

src/redux/index.js

Bu dosyada reducer’larımızı combine ediyoruz. Bunun sonucunu createStore fonksiyonuna parametre geçeceğiz. Şimdilik bir tane reducer’ımız olduğu için onu gönderiyoruz.

src/redux/configureStore.js

İndex dosyasından gelen reducer’ları burada ,configureStore fonksiyonunda , createStore fonksiyonuna parametre veriyoruz. Bu kısımda middleware’lerimizi de ekleyebiliriz.

src/index.js

Store’umuzu oluşturduktan sonra uygulamamızı Provider nesnesi ile sarmallayıp store’u parametre olarak gönderiyoruz.

src/components/TodoAdd.js

mapDispatchToProps metodunda ekleme action’ını tanımladık. State ile bir işimiz olmadığı için connect fonksiyonunun ilk parametresini null geçtik.

Component’imiz çok basit bir işlem yapıyor. İnput’ta yapılan her değişkliği component’in state’inde tanımlanan todo değişkenine set ediyor. Butona tıklandığı zaman da bu değeri ,add action’ını kullanarak parametre geçiyor. Bu işlem sonucunda arka tarafta ,dispatch metodumuz action’ı reducer’ımıza parametre geçerek ilgili işlemi yapıyor.

src/components/TodoSearch.js

Bu component’in state’inde aranan değeri tutuyoruz. Bu aranan değer input’ta ,her değiştiğinde bir action tetikleniyor. Bu işlemden sonra reducer’ımızda filtreleme işlemi gerçekleşerek olası sonuçlar filterTodos state’ine set ediliyor. Eğer aranan değer boş ise tüm todo’ları değilse -demek ki aranan bir değer var- filtre sonucunu TodoList component’ine gönderiyoruz.

src/components/TodoList.js

Bu component’te ise parent component’ten gelen todo’ları map fonksiyonu ile gösteriyoruz. Bir todo’nun silinme işlemini yine ekleme işlemi gibi bir butona bağlıyoruz. Bu butona tıklandığında ilgili todo ile beraber action fırlatılıyor. Reducer’a giden action TODO_REMOVE case’ine düştükten sonra filtreleme işlemi yapılarak yeni state geri dönülüyor. State değiştiği için todos state’ine abone olan tüm component’ler kendini render ediyor.

Bu uygulamada ,hem redux hemde component diriling yöntemlerini kullanarak state’lerimizi yönettik. TodoSearch component’inden TodoList component’ine ,todos state’ini parametre geçerek component diriling yöntemini, todos state’ini redux mağazasından TodoSearch component’imize göndererek redux store yöntemini kullandık.

uygulamamızı canlı inceleyebilirsiniz.

Örneğe buradan ulaşabilirsiniz.

Sonraki yazımda redux middleware’lerini , redux-thunk ile asenkron işlemleri anlatacağım. Görüşmek üzere.

--

--