Redux bir state management (state yönetimi) kütüphanesidir. React üzerinde bir proje yaptığınızı düşünelim başlarda az sayıda component az sayıda props ve az sayıda state her şey güzel giderken ilerleyen aşamalarda projeniz büyüyüp karmaşıklaşmaya başladığında ortaya bu statelerin yönetiminin çok zorlaştığı çıkar. İç içe birbirini çalıştıran componentlerin çoğu kullanmadıkları halde stateleri sadece taşıma görevi üstlenir bu nedenle de state yönetimi güçleşir. Peki redux bu işi nasıl çözüyor.
Redux bütün stateleri tek bir javascript objesi olan store(market) içerisinde tutar böylelikle her bileşen state bilgilerini storedan erişim sağlama durumunda kalır. Bütün veriler store'dan geldiği için hangi state nereden gelmiş gibi bir veri takibine gerek kalmaz, oluşan kod Redux ile daha temiz bir hale gelmiş olur.
Redux üç yapıya bağlı olarak çalışır bunlar Store, Actionlar ve Reducer olarak adlandırılır.
Store uygulumanızın çalışması için ihtiyaç duyduğu bütün dataları tutabililir bunları değiştirmek içinse argüman olarak ilgili state'i ve action'u içine alan bir fonksiyona ihtiyaç duyarsınız bu fonksiyon update edilmş state'i return eder bu fonksiyona giren actionlar değişikliğin oluşmasını istediğimiz anda olacak olan olay diyebiliriz.Reducer ise tam anlamıyla bu fonksiyondur.
Basit bir dille kurduğunuz reducer istenilen action gerçekleştiğinde state'i update eder
Bir redux uygulaması kurmak için adımlar aşşağıdaki gibi sıralanabilir.
- Store Dizaynı
- Actionların tanımlanması
- Reducerların oluşturulması
- Store Kurulumu
Bir bug tracker uygulaması düşünün bu uygulamaya bulduğumuz bugları gireceğiz ve durumlarını çözüm aşamasında çözülmedi veya çözüldü gibi değiştirebileceğimiz bir uygulama. Bu adımları teker teker başlıklar halinde açıklayacağım ve açıklamalar bu bug tracker örneği üzerinden ilerleyecektir.
Store güncel verileri tutacağı için örnek uygulamamızın store yapısı bu şekilide olabilir.
{
bugs: [
{
id: 1,
description: "",
resolved: false
}
],
currentUser: {}
}
Actionlar o anda ne olduğunu açıklayan javascript objeleridir.
{
type: "ADD_BUG",
payload: {
description: "..."
}
}
{
type: "REMOVE_BUG",
payload: {
id: 1
}
}
type reduxın action objelerinde yazmanızı beklediği tek özelliktir actionlarınıza type mutlaka ekleyin
Yukarıdaki örnekte yazılan payload kısmı zorunlu olan type dışarısında bulunacak bütün özellikleri tutacağımız kısım olacak ve içerisinde o action için gerekli minimum özellikleri tutmalıdır. Typelar yukarıda göründüğü casing ile yazılması zorunlu değildir hatta string bile olması şart değildir isterseniz sayılara atayabilirsiniz fakat en yaygın kullanımı bu casing'dir.
Reducerlar yukarıda söylediğimiz gibi değişiklikleri yapan fonksiyonlardır mevcut state'i ve gerçekleşen actionu parametre olarak alırlar ve actiona göre state değişikliklerini gerçekleştirip yeni state'i return ederler.
//reducer.js
let lastId = 0;
export default function reducer(state = [], action){
switch (action.type) {
case "ADD_BUG":
return[
...state,
{
id: ++lastId,
descripton: action.payload.description,
resolved:false
}
];
case "REMOVE_BUG":
return state.filter(bug => bug.id !== action.payload.id);
default:
return state;
}
}
//store.js
import { createStore } from 'redux';
import reducer from 'reducer.js bulunduğu konum';
const store = createStore(reducer);
export default store;
store kurulumu bu şekildedir.
Bir önceki başlıkta ele aldığımız örneğin basit redux mantığını oturtalım.
export const BUG_ADDED = "bugAdded";
export const BUG_REMOVED = "bugRemoved";
export const BUG_RESOLVED = "bugResolved";
import * as actions from "./actionTypes.js"
export const bugAdded = description =>({
type: actions.BUG_ADDED,
payload: {
description //description: description ile aynı şey
}
})
export const bugResolved = id => ({
type: actions.BUG_RESOLVED,
payload: {
id //id: id demek oluyor ikisininde ismi aynı olduğunda bu şekilde de kullanılabilir
}
})
import * as actions from "./actionTypes.js"
let lastId = 0;
export default function reducer(state = [], action){
switch (action.type) {
case actions.BUG_ADDED:
return[
...state,
{
id: ++lastId,
descripton: action.payload.description,
resolved:false
}
];
case actions.BUG_REMOVED:
return state.filter(bug => bug.id !== action.payload.id);
case actions.BUG_RESOLVED:
return state.map(bug => bug.id !== action.payload.id ? bug : {...bug, resolved: true});
default:
return state;
}
}
import { createStore } from 'redux';
import reducer from 'reducer.js bulunduğu konum';
const store = createStore(reducer);
export default store;
import store from "./store.js"
import { bugAdded, bugResolved } from "./actions.js";
store.dispatch(bugAdded("Bug1"));
store.dispatch(bugResolved(1));
console.log(store.getState());
Mükemmel..