Redux - Hızlı Kılavuz

Redux, JavaScript uygulamaları için öngörülebilir bir durum kapsayıcısıdır. Uygulama büyüdükçe, onu düzenli tutmak ve veri akışını sürdürmek zorlaşır. Redux, uygulamanın durumunu Store adlı tek bir global nesne ile yöneterek bu sorunu çözer. Redux temel ilkeleri, uygulamanız boyunca tutarlılığın korunmasına yardımcı olur, bu da hata ayıklamayı ve testi kolaylaştırır.

Daha da önemlisi, size zaman yolculuğu yapan bir hata ayıklayıcı ile birlikte canlı kod düzenlemesi sağlar. React, Angular, Vue vb. Gibi herhangi bir görünüm katmanına uyum sağlamak için esnektir.

Redux İlkeleri

Redux'un tahmin edilebilirliği, aşağıda verilen en önemli üç ilkeyle belirlenir -

Tek Gerçeğin Kaynağı

Tüm uygulamanızın durumu, tek bir depodaki bir nesne ağacında saklanır. Tüm uygulama durumu tek bir ağaçta depolandığından, hata ayıklamayı kolaylaştırır ve geliştirmeyi hızlandırır.

Durum Salt Okunur

Durumu değiştirmenin tek yolu, ne olduğunu açıklayan bir nesne, bir eylem yaymaktır. Bu, hiç kimsenin başvurunuzun durumunu doğrudan değiştiremeyeceği anlamına gelir.

Saf işlevlerle değişiklikler yapılır

Durum ağacının eylemlerle nasıl dönüştürüldüğünü belirtmek için saf indirgeyiciler yazarsınız. İndirgeyici, durum değişikliğinin gerçekleştiği merkezi bir yerdir. Reducer, durumu ve eylemi argüman olarak alan ve yeni güncellenmiş bir durum döndüren bir işlevdir.

Redux'u kurmadan önce we have to install Nodejs and NPM. Aşağıda, yüklemenize yardımcı olacak talimatlar verilmiştir. Cihazınızda zaten Nodejs ve NPM kuruluysa bu adımları atlayabilirsiniz.

  • Ziyaret etmek https://nodejs.org/ ve paket dosyasını yükleyin.

  • Yükleyiciyi çalıştırın, talimatları izleyin ve lisans sözleşmesini kabul edin.

  • Çalıştırmak için cihazınızı yeniden başlatın.

  • Komut istemini açıp node -v yazarak başarılı kurulumu kontrol edebilirsiniz. Bu size sisteminizdeki en son Node sürümünü gösterecektir.

  • Npm'nin başarıyla yüklenip yüklenmediğini kontrol etmek için, size en son npm sürümünü döndüren npm –v yazabilirsiniz.

Redux'u kurmak için aşağıdaki adımları takip edebilirsiniz -

Redux'u kurmak için komut isteminizde aşağıdaki komutu çalıştırın.

npm install --save redux

Redux'u react uygulamasıyla kullanmak için, aşağıdaki gibi ek bir bağımlılık kurmanız gerekir -

npm install --save react-redux

Redux için geliştirici araçlarını yüklemek için, aşağıdakileri bağımlılık olarak yüklemeniz gerekir -

Redux dev-tools'u yüklemek için komut isteminizde aşağıdaki komutu çalıştırın.

npm install --save-dev redux-devtools

Redux geliştirme araçlarını yüklemek ve projenize entegre etmek istemiyorsanız, Redux DevTools Extension Chrome ve Firefox için.

Uygulamamızın durumunun adı verilen düz bir nesne tarafından tanımlandığını varsayalım. initialState aşağıdaki gibidir -

const initialState = {
   isLoading: false,
   items: [],
   hasError: false
};

Uygulamanızdaki her kod parçası bu durumu değiştiremez. Durumu değiştirmek için bir eylem göndermeniz gerekir.

Eylem nedir?

Eylem, bir tür özelliği ile değişikliğe neden olma niyetini açıklayan düz bir nesnedir. Ne tür bir eylemin gerçekleştirildiğini söyleyen bir type özelliğine sahip olmalıdır. Eylem komutu aşağıdaki gibidir -

return {
   type: 'ITEMS_REQUEST', //action type
   isLoading: true //payload information
}

Eylemler ve durumlar, Reducer adı verilen bir işlev tarafından bir arada tutulur. Değişikliğe neden olmak amacıyla bir eylem gönderilir. Bu değişiklik redüktör tarafından yapılır. Redüktör, Redux'daki durumları değiştirmenin tek yoludur, bu da onu daha öngörülebilir, merkezi ve hata ayıklanabilir hale getirir. 'ITEMS_REQUEST' eylemini işleyen bir indirgeme işlevi aşağıdaki gibidir -

const reducer = (state = initialState, action) => { //es6 arrow function
   switch (action.type) {
      case 'ITEMS_REQUEST':
         return Object.assign({}, state, {
            isLoading: action.isLoading
         })
      default:
         return state;
   }
}

Redux, uygulama durumunu tutan tek bir depoya sahiptir. Kodunuzu veri işleme mantığına göre bölmek istiyorsanız, Redux'daki mağazalar yerine indirgeyicilerinizi bölmeye başlamalısınız.

Redüktörleri nasıl bölebileceğimizi ve bunu mağazayla nasıl birleştirebileceğimizi bu öğreticide daha sonra tartışacağız.

Redux bileşenleri aşağıdaki gibidir -

Redux, tek yönlü veri akışını takip eder. Bu, uygulama verilerinizin tek yönlü bağlanma veri akışını izleyeceği anlamına gelir. Uygulama büyüdükçe ve karmaşık hale geldikçe, uygulamanızın durumu üzerinde hiçbir kontrolünüz yoksa sorunları yeniden üretmek ve yeni özellikler eklemek zordur.

Redux, durum güncellemesinin nasıl ve ne zaman yapılacağına ilişkin kısıtlamayı uygulayarak kodun karmaşıklığını azaltır. Bu şekilde, güncellenmiş durumları yönetmek kolaydır. Redux'un üç prensibi olarak kısıtlamaları zaten biliyoruz. Aşağıdaki şema, Redux veri akışını daha iyi anlamanıza yardımcı olacaktır -

  • Bir kullanıcı uygulamayla etkileşim kurduğunda bir eylem gönderilir.

  • Kök azaltıcı işlevi, mevcut durum ve gönderilen eylemle çağrılır. Kök indirgeyici görevi, nihayetinde yeni bir durum döndüren daha küçük indirgeme işlevleri arasında bölebilir.

  • Mağaza, geri arama işlevlerini yürüterek görünümü bilgilendirir.

  • Görünüm güncellenmiş durumu alabilir ve yeniden oluşturabilir.

Mağaza, Redux'da değişmez bir nesne ağacıdır. Depo, uygulamanın durumunu tutan bir durum kapsayıcısıdır. Redux, uygulamanızda yalnızca tek bir mağazaya sahip olabilir. Redux'te bir mağaza oluşturulduğunda, indirgeyiciyi belirtmeniz gerekir.

Nasıl mağaza oluşturabileceğimize bakalım. createStoreRedux'dan yöntem. Aşağıda gösterildiği gibi mağaza oluşturma sürecini destekleyen Redux kitaplığından createStore paketinin içe aktarılması gerekir -

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

CreateStore işlevinin üç bağımsız değişkeni olabilir. Aşağıdaki sözdizimidir -

createStore(reducer, [preloadedState], [enhancer])

İndirgeyici, uygulamanın bir sonraki durumunu döndüren bir işlevdir. PreloadedState, isteğe bağlı bir bağımsız değişkendir ve uygulamanızın ilk durumudur. Bir güçlendirici aynı zamanda isteğe bağlı bir argümandır. Üçüncü taraf yetenekleriyle mağazanızı geliştirmenize yardımcı olacaktır.

Bir mağazanın aşağıda verildiği gibi üç önemli yöntemi vardır -

getState

Redux mağazanızın mevcut durumunu almanıza yardımcı olur.

GetState için sözdizimi aşağıdaki gibidir -

store.getState()

sevk etmek

Uygulamanızdaki bir durumu değiştirmek için bir eylem göndermenize olanak tanır.

Gönderim için sözdizimi aşağıdaki gibidir -

store.dispatch({type:'ITEMS_REQUEST'})

abone ol

Redux mağazasının bir eylem gönderildiğinde arayacağı bir geri aramayı kaydetmenize yardımcı olur. Redux durumu güncellenir güncellenmez, görünüm otomatik olarak yeniden işlenecektir.

Gönderim için sözdizimi aşağıdaki gibidir -

store.subscribe(()=>{ console.log(store.getState());})

Abone olma işlevinin, dinleyicinin aboneliğini iptal etmek için bir işlev döndürdüğünü unutmayın. Dinleyicinin aboneliğinden çıkmak için aşağıdaki kodu kullanabiliriz -

const unsubscribe = store.subscribe(()=>{console.log(store.getState());});
unsubscribe();

Redux resmi belgelerine göre, mağaza için tek bilgi kaynağı eylemlerdir. Uygulamanızdan depolamak için bir miktar bilgi taşır.

Daha önce tartışıldığı gibi, eylemler, gerçekleştirilen eylemin türünü belirtmek için bir type özniteliğine sahip olması gereken düz JavaScript nesnesidir. Bize ne olduğunu anlatır. Türler, uygulamanızda aşağıda belirtildiği gibi dize sabitleri olarak tanımlanmalıdır -

const ITEMS_REQUEST = 'ITEMS_REQUEST';

Bu tür özniteliğin dışında, bir eylem nesnesinin yapısı tamamen geliştiriciye bağlıdır. Eylem nesnenizi olabildiğince hafif tutmanız ve yalnızca gerekli bilgileri iletmeniz önerilir.

Depoda herhangi bir değişikliğe neden olmak için, önce store.dispatch () işlevini kullanarak bir eylem göndermeniz gerekir. Eylem nesnesi aşağıdaki gibidir -

{ type: GET_ORDER_STATUS , payload: {orderId,userId } }
{ type: GET_WISHLIST_ITEMS, payload: userId }

Eylem Oluşturucular

Eylem oluşturucular, bir eylem nesnesi oluşturma sürecini kapsayan işlevlerdir. Bu işlevler basitçe bir eylem olan düz bir Js nesnesi döndürür. Temiz kod yazmayı teşvik eder ve yeniden kullanılabilirliğin sağlanmasına yardımcı olur.

Bir eylem göndermenize izin veren eylem oluşturucu hakkında bilgi edelim, ‘ITEMS_REQUEST’bu, sunucudan ürün öğeleri listesi verilerini talep eder. Bu aradaisLoading 'ITEMS_REQUEST' eylem türünde, öğelerin yüklendiğini ve sunucudan hala veri alınmadığını belirtmek için indirgeyicide durumu doğru hale getirilir.

Başlangıçta, isLoading durumu yanlıştı initialStatehiçbir şeyin yüklenmediğini varsayan nesne. Tarayıcıda veri alındığında, isLoading durumu, karşılık gelen indirgeyicide 'ITEMS_REQUEST_SUCCESS' eylem türünde yanlış olarak döndürülür. Bu durum, veri talebi açıkken sayfanızda yükleyici / mesaj görüntülemek için react bileşenlerinde bir destek olarak kullanılabilir. Eylem yaratıcısı aşağıdaki gibidir -

const ITEMS_REQUEST = ‘ITEMS_REQUEST’ ;
const ITEMS_REQUEST_SUCCESS = ‘ITEMS_REQUEST_SUCCESS’ ;
export function itemsRequest(bool,startIndex,endIndex) {
   let payload = {
      isLoading: bool,
      startIndex,
      endIndex
   }
   return {
      type: ITEMS_REQUEST,
      payload
   }
}
export function itemsRequestSuccess(bool) {
   return {
      type: ITEMS_REQUEST_SUCCESS,
      isLoading: bool,
   }
}

Bir gönderme işlevini çağırmak için, işlevi göndermek üzere bir bağımsız değişken olarak eylemi iletmeniz gerekir.

dispatch(itemsRequest(true,1, 20));
dispatch(itemsRequestSuccess(false));

Doğrudan store.dispatch () kullanarak bir eylem gönderebilirsiniz. Ancak, buna react-Redux helper yöntemiyle erişmeniz daha olasıdır.connect(). Ayrıca kullanabilirsinbindActionCreators() birçok eylem oluşturucuyu gönderme işlevi ile bağlama yöntemi.

İşlev, argümanlar olarak adlandırılan girdileri alan ve dönüş değeri olarak bilinen bazı çıktılar üreten bir işlemdir. Aşağıdaki kurallara uyan bir işlev saf olarak adlandırılır -

  • Bir işlev, aynı bağımsız değişkenler için aynı sonucu döndürür.

  • Değerlendirmesinin herhangi bir yan etkisi yoktur, yani girdi verilerini değiştirmez.

  • Yerel ve global değişkenlerde mutasyon yok.

  • Global bir değişken gibi dış duruma bağlı değildir.

İşleve girdi olarak geçirilen değerin iki katını döndüren bir işlev örneğini ele alalım. Genel olarak, f (x) => x * 2 şeklinde yazılır. 2 bağımsız değişken değeriyle bir işlev çağrılırsa, çıktı 4 olur, f (2) => 4.

Fonksiyonun tanımını JavaScript'te aşağıda gösterildiği gibi yazalım -

const double = x => x*2; // es6 arrow function
console.log(double(2));  // 4

Here, double is a pure function.

Redux'teki üç ilkeye göre, değişiklikler saf bir fonksiyon, yani Redux'ta redüktör tarafından yapılmalıdır. Şimdi, bir indirgeyicinin neden saf bir işlev olması gerektiğine dair bir soru ortaya çıkıyor.

Diyelim ki, türü olan bir eylem göndermek istiyorsunuz 'ADD_TO_CART_SUCCESS' Sepete ekle butonuna tıklayarak alışveriş sepeti uygulamanıza bir ürün eklemek için.

Redüktörün sepetinize aşağıdaki gibi bir ürün eklediğini varsayalım -

const initialState = {
   isAddedToCart: false;
}
const addToCartReducer = (state = initialState, action) => { //es6 arrow function
   switch (action.type) {
      case 'ADD_TO_CART_SUCCESS' :
         state.isAddedToCart = !state.isAddedToCart; //original object altered
         return state;
      default:
         return state;
   }
}
export default addToCartReducer ;

Varsayalım, isAddedToCart bir Boolean değeri döndürerek öğe için 'sepete ekle' düğmesini ne zaman devre dışı bırakacağınıza karar vermenize olanak tanıyan durum nesnesi üzerindeki bir özelliktir ‘true or false’. Bu, kullanıcının aynı ürünü birden çok kez eklemesini engeller. Şimdi, yeni bir nesne döndürmek yerine, yukarıdaki gibi durumdaki isAddedToCart prop'unu değiştiriyoruz. Şimdi sepete bir ürün eklemeye çalışırsak hiçbir şey olmuyor. Sepete ekle düğmesi devre dışı bırakılmayacak.

Bu davranışın nedeni aşağıdaki gibidir -

Redux, eski ve yeni nesneleri her iki nesnenin bellek konumuna göre karşılaştırır. Herhangi bir değişiklik olursa redüktörden yeni bir nesne bekler. Ayrıca herhangi bir değişiklik olmazsa eski nesneyi geri almayı bekler. Bu durumda aynıdır. Bu nedenle Redux hiçbir şeyin olmadığını varsayar.

Bu nedenle, redüktörün Redux'da saf bir fonksiyon olması gerekir. Aşağıdaki, mutasyon olmadan yazmanın bir yoludur -

const initialState = {
   isAddedToCart: false;
}
const addToCartReducer = (state = initialState, action) => { //es6 arrow function
   switch (action.type) {
      case 'ADD_TO_CART_SUCCESS' :
         return {
            ...state,
            isAddedToCart: !state.isAddedToCart
         }
      default:
         return state;
   }
}
export default addToCartReducer;

Redüktörler, Redux'ta saf bir işlevdir. Saf fonksiyonlar tahmin edilebilir. Redüktörler, Redux'ta durumları değiştirmenin tek yoludur. Mantık ve hesaplamalar yazabileceğiniz tek yer orasıdır. İndirgeyici işlevi, uygulamanın önceki durumunu ve gönderilen eylemi kabul eder, sonraki durumu hesaplar ve yeni nesneyi döndürür.

Aşağıdaki birkaç şey asla redüktörün içinde yapılmamalıdır -

  • Fonksiyon argümanlarının mutasyonu
  • API çağrıları ve yönlendirme mantığı
  • Saf olmayan işlevi çağırma, örneğin Math.random ()

Aşağıdakiler bir redüktörün sözdizimidir -

(state,action) => newState

Eylem yaratıcıları modülünde tartışılan ürün öğelerinin listesini bir web sayfasında gösterme örneğine devam edelim. İndirgeyicisinin nasıl yazılacağını aşağıda görelim.

const initialState = {
   isLoading: false,
   items: []
};
const reducer = (state = initialState, action) => {
   switch (action.type) {
      case 'ITEMS_REQUEST':
         return Object.assign({}, state, {
            isLoading: action.payload.isLoading
         })
      case ‘ITEMS_REQUEST_SUCCESS':
         return Object.assign({}, state, {
            items: state.items.concat(action.items),
            isLoading: action.isLoading
         })
      default:
         return state;
   }
}
export default reducer;

İlk olarak eğer state 'initialState' olarak ayarlamazsanız, Redux tanımlanmamış durumdaki redüktörü çağırır. Bu kod örneğinde, JavaScript'in concat () işlevi, var olan diziyi değiştirmeyen 'ITEMS_REQUEST_SUCCESS'de kullanılır; bunun yerine yeni bir dizi döndürür.

Bu şekilde devletin mutasyona uğramasını önleyebilirsiniz. Asla doğrudan eyalete yazmayın. 'ITEMS_REQUEST'te, alınan eylemin durum değerini ayarlamamız gerekiyor.

Mantığımızı redüktörde yazabileceğimiz ve onu mantıksal veri bazında bölebileceğimiz zaten tartışılmıştır. Büyük bir uygulama ile uğraşırken redüktörleri nasıl bölerek nasıl kök redüktör olarak birleştirebileceğimizi görelim.

Diyelim ki, bir kullanıcının ürün sipariş durumuna erişebileceği ve istek listesi bilgilerini görebileceği bir web sayfası tasarlamak istiyoruz. Mantığı farklı redüktör dosyalarında ayırabilir ve bağımsız olarak çalışmasını sağlayabiliriz. Bazı sipariş kimliği ve kullanıcı kimliğine karşılık gelen sipariş durumunu almak için GET_ORDER_STATUS eyleminin gönderildiğini varsayalım.

/reducer/orderStatusReducer.js
import { GET_ORDER_STATUS } from ‘../constants/appConstant’;
export default function (state = {} , action) {
   switch(action.type) {
      case GET_ORDER_STATUS:
         return { ...state, orderStatusData: action.payload.orderStatus };
      default:
         return state;
   }
}

Benzer şekilde, kullanıcının bir kullanıcıya ilişkin istek listesi bilgilerini almak için GET_WISHLIST_ITEMS eyleminin gönderildiğini varsayın.

/reducer/getWishlistDataReducer.js
import { GET_WISHLIST_ITEMS } from ‘../constants/appConstant’;
export default function (state = {}, action) {
   switch(action.type) {
      case GET_WISHLIST_ITEMS:
         return { ...state, wishlistData: action.payload.wishlistData };
      default:
         return state;
   }
}

Şimdi, Redux combinesini kullanarak her iki redüktörü birleştirebiliriz. CombinReducers, değerleri farklı indirgeme işlevleri olan bir nesneyi döndüren bir işlev oluşturur. İndeks düşürücü dosyasındaki tüm redüktörleri içe aktarabilir ve bunları ilgili isimleriyle birlikte bir nesne olarak birleştirebilirsiniz.

/reducer/index.js
import { combineReducers } from ‘redux’;
import OrderStatusReducer from ‘./orderStatusReducer’;
import GetWishlistDataReducer from ‘./getWishlistDataReducer’;

const rootReducer = combineReducers ({
   orderStatusReducer: OrderStatusReducer,
   getWishlistDataReducer: GetWishlistDataReducer
});
export default rootReducer;

Şimdi, bu rootReducer'ı createStore yöntemine aşağıdaki gibi iletebilirsiniz -

const store = createStore(rootReducer);

Redux'un kendisi eşzamanlıdır, öyleyse async gibi işlemler network requestRedux ile çalışmak? Burada ara yazılımlar işe yarar. Daha önce tartışıldığı gibi, indirgeyiciler, tüm yürütme mantığının yazıldığı yerdir. Reducer'ın, eylemi göndermeden önce ve sonra uygulamayı kimin yaptığı, ne kadar zaman aldığı veya uygulamanın durumunu günlüğe kaydettiği ile hiçbir ilgisi yoktur.

Bu durumda, Redux ara yazılım işlevi, indirgeyiciye ulaşmadan önce gönderilen eylemle etkileşime girecek bir ortam sağlar. Özelleştirilmiş ara yazılım işlevleri, bazı mantığı saran yüksek dereceli işlevler (başka bir işlevi döndüren bir işlev) yazarak oluşturulabilir. Yeni işlevler eklemek için birden çok ara yazılım bir araya getirilebilir ve her bir ara yazılım, önce ve sonra gelenler hakkında bilgi gerektirmez. Gönderilen eylem ile indirgeyici arasında bir yerde ara yazılımlar hayal edebilirsiniz.

Genel olarak, ara yazılımlar, uygulamanızdaki eşzamansız eylemlerle başa çıkmak için kullanılır. Redux, özel ara yazılımların yanı sıra redux-thunk ve redux-promise gibi Redux ara yazılımlarını kullanmamıza izin veren applyMiddleware adlı API'yi sağlar. Depolamak için ara yazılımlar uygular. ApplyMiddleware API kullanmanın sözdizimi şudur:

applyMiddleware(...middleware)

Ve bu, aşağıdaki gibi saklamak için uygulanabilir -

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
const store = createStore(rootReducer, applyMiddleware(thunk));

Ara yazılımlar, bir eylem nesnesi yerine bir işlev döndüren bir eylem dağıtıcısı yazmanıza izin verir. Aynısı için örnek aşağıda gösterilmiştir -

function getUser() {
   return function() {
      return axios.get('/get_user_details');
   };
}

Koşullu gönderim, ara katman yazılımına yazılabilir. Her ara yazılım, deponun gönderimini alır, böylece yeni eylem gönderebilirler ve getState, geçerli duruma erişebilmeleri ve bir işlev döndürebilmeleri için bağımsız değişken olarak işlev görür. Bir iç işlevden herhangi bir dönüş değeri, gönderme işlevinin değeri olarak kullanılabilir olacaktır.

Aşağıda bir ara yazılımın sözdizimi verilmiştir -

({ getState, dispatch }) => next => action

GetState işlevi, mevcut duruma bağlı olarak yeni verilerin getirilip getirilmeyeceğine veya önbellek sonucunun döndürülmesine karar vermek için kullanışlıdır.

Özel bir ara yazılım kaydedici işlevi örneğini görelim. Sadece eylemi ve yeni durumu günlüğe kaydeder.

import { createStore, applyMiddleware } from 'redux'
import userLogin from './reducers'

function logger({ getState }) {
   return next => action => {
      console.log(‘action’, action);
      const returnVal = next(action);
      console.log('state when action is dispatched', getState()); 
      return returnVal;
   }
}

Şimdi, aşağıdaki kod satırını yazarak kaydedici ara yazılımını mağazaya uygulayın -

const store = createStore(userLogin , initialState=[ ] , applyMiddleware(logger));

Aşağıdaki kodu kullanarak gönderilen eylemi ve yeni durumu kontrol etmek için bir eylem gönderin -

store.dispatch({
   type: 'ITEMS_REQUEST', 
	isLoading: true
})

Yükleyiciyi ne zaman göstereceğinizi veya gizleyeceğinizi idare edebileceğiniz başka bir ara yazılım örneği aşağıda verilmiştir. Bu ara yazılım, herhangi bir kaynak talep ettiğinizde yükleyiciyi gösterir ve kaynak isteği tamamlandığında onu gizler.

import isPromise from 'is-promise';

function loaderHandler({ dispatch }) {
   return next => action => {
      if (isPromise(action)) {
         dispatch({ type: 'SHOW_LOADER' });
         action
            .then(() => dispatch({ type: 'HIDE_LOADER' }))
            .catch(() => dispatch({ type: 'HIDE_LOADER' }));
      }
      return next(action);
   };
}
const store = createStore(
   userLogin , initialState = [ ] , 
   applyMiddleware(loaderHandler)
);

Redux-Devtools, Redux uygulamaları için bize hata ayıklama platformu sağlıyor. Zaman yolculuğu hata ayıklaması ve canlı düzenleme yapmamızı sağlar. Resmi belgelerdeki bazı özellikler aşağıdaki gibidir -

  • Her durumu ve eylem yükünü incelemenizi sağlar.

  • Eylemleri "iptal ederek" zamanda geriye gitmenizi sağlar.

  • İndirgeyici kodunu değiştirirseniz, her "aşamalı" eylem yeniden değerlendirilecektir.

  • Redüktörler atarsa, hatayı ve bunun hangi eylem sırasında gerçekleştiğini belirleyebiliriz.

  • KalıcıState () mağaza geliştiricisi ile, sayfa yeniden yüklemelerinde hata ayıklama oturumlarını sürdürebilirsiniz.

Aşağıda verildiği gibi Redux geliştirme araçlarının iki çeşidi vardır -

Redux DevTools - Paket halinde kurulabilir ve aşağıda belirtildiği gibi uygulamanıza entegre edilebilir -

https://github.com/reduxjs/redux-devtools/blob/master/docs/Walkthrough.md#manual-integration

Redux DevTools Extension - Redux için aynı geliştirici araçlarını uygulayan bir tarayıcı uzantısı aşağıdaki gibidir -

https://github.com/zalmoxisus/redux-devtools-extension

Şimdi Redux geliştirme aracının yardımıyla eylemleri nasıl atlayabileceğimizi ve zamanda geriye nasıl gidebileceğimizi kontrol edelim. Aşağıdaki ekran görüntüleri, öğelerin listesini almak için daha önce gönderdiğimiz eylemleri açıklar. Burada denetçi sekmesinde gönderilen eylemleri görebiliriz. Sağ tarafta, size durum ağacındaki farkı gösteren Demo sekmesini görebilirsiniz.

Kullanmaya başladığınızda bu araca aşina olacaksınız. Sadece bu Redux eklenti aracından gerçek kodu yazmadan bir eylem gönderebilirsiniz. Son satırdaki Dağıtıcı seçeneği bu konuda size yardımcı olacaktır. Öğelerin başarıyla getirildiği son işlemi kontrol edelim.

Sunucudan yanıt olarak bir dizi nesne aldık. Sayfamızdaki listeyi görüntülemek için tüm veriler mevcuttur. Aynı zamanda sağ üst taraftaki durum sekmesine tıklayarak mağazanın durumunu da takip edebilirsiniz.

Önceki bölümlerde, zamanda yolculuk hata ayıklamasını öğrendik. Şimdi bir eylemi nasıl atlayacağımızı kontrol edelim ve uygulamamızın durumunu analiz etmek için zamanda geri dönelim. Herhangi bir eylem türüne tıkladığınızda, iki seçenek: 'Atla' ve 'Atla' görünecektir.

Belirli bir eylem türünde atla düğmesine tıklayarak belirli eylemi atlayabilirsiniz. Sanki eylem hiç olmamış gibi davranır. Belirli eylem türlerinde atlama düğmesine tıkladığınızda, sizi o eylemin gerçekleştiği duruma götürür ve sırayla kalan tüm eylemleri atlar. Bu şekilde, belirli bir eylem gerçekleştiğinde durumu koruyabileceksiniz. Bu özellik, uygulamada hata ayıklama ve hataları bulmada kullanışlıdır.

Son eylemi atladık ve arka plandaki tüm listeleme verileri kayboldu. Öğelerin verilerinin gelmediği ve uygulamamızın sayfada görüntülenecek verisi olmadığı zamana kadar geri gider. Aslında kodlamayı ve hata ayıklamayı kolaylaştırır.

Redux kodunu test etmek, çoğunlukla fonksiyon yazdığımız için kolaydır ve çoğu saftır. Böylece onları alay etmeden bile test edebiliriz. Burada JEST'i test motoru olarak kullanıyoruz. Düğüm ortamında çalışır ve DOM'a erişmez.

JEST'i aşağıda verilen kod ile kurabiliriz -

npm install --save-dev jest

Babel ile yüklemeniz gerekir babel-jest aşağıdaki gibi -

npm install --save-dev babel-jest

Ve .babelrc dosyasındaki babel-preset-env özelliklerini kullanmak için aşağıdaki gibi yapılandırın -

{ 
   "presets": ["@babel/preset-env"] 
}
And add the following script in your package.json:
{ 
   //Some other code 
   "scripts": {
      //code
      "test": "jest", 
      "test:watch": "npm test -- --watch" 
   }, 
   //code 
}

En sonunda, run npm test or npm run test. Aksiyon yaratıcıları ve indirgemeciler için nasıl test senaryoları yazabileceğimize bir bakalım.

Action Creators için Test Örnekleri

Aşağıda gösterildiği gibi bir eylem yaratıcınız olduğunu varsayalım -

export function itemsRequestSuccess(bool) {
   return {
      type: ITEMS_REQUEST_SUCCESS,
      isLoading: bool,
   }
}

Bu eylem oluşturucu aşağıda belirtildiği gibi test edilebilir -

import * as action from '../actions/actions';
import * as types from '../../constants/ActionTypes';

describe('actions', () => {
   it('should create an action to check if item is loading', () => { 
      const isLoading = true, 
      const expectedAction = { 
         type: types.ITEMS_REQUEST_SUCCESS, isLoading 
      } 
      expect(actions.itemsRequestSuccess(isLoading)).toEqual(expectedAction) 
   })
})

Redüktörler için Test Durumları

Redüktörün eylem uygulandığında yeni bir duruma dönmesi gerektiğini öğrendik. Yani redüktör bu davranış üzerinde test edilir.

Aşağıda belirtildiği gibi bir redüktör düşünün -

const initialState = {
   isLoading: false
};
const reducer = (state = initialState, action) => {
   switch (action.type) {
      case 'ITEMS_REQUEST':
         return Object.assign({}, state, {
            isLoading: action.payload.isLoading
         })
      default:
         return state;
   }
}
export default reducer;

Redüktörün üzerinde test etmek için, durumu ve eylemi redüktöre iletmemiz ve aşağıda gösterildiği gibi yeni bir duruma geri dönmemiz gerekir -

import reducer from '../../reducer/reducer' 
import * as types from '../../constants/ActionTypes'

describe('reducer initial state', () => {
   it('should return the initial state', () => {
      expect(reducer(undefined, {})).toEqual([
         {
            isLoading: false,
         }
      ])
   })
   it('should handle ITEMS_REQUEST', () => {
      expect(
         reducer(
            {
               isLoading: false,
            },
            {
               type: types.ITEMS_REQUEST,
               payload: { isLoading: true }
            }
         )
      ).toEqual({
         isLoading: true
      })
   })
})

Test senaryosu yazmaya aşina değilseniz, JEST'in temellerini kontrol edebilirsiniz .

Önceki bölümlerde Redux nedir ve nasıl çalıştığını öğrendik. Şimdi görünüm bölümünün Redux ile entegrasyonunu kontrol edelim. Redux'a herhangi bir görünüm katmanı ekleyebilirsiniz. React library ve Redux'u da tartışacağız.

Diyelim ki, çeşitli reaksiyon bileşenlerinin aynı verileri, üst düzey bileşenden aşağıya kadar tüm bileşenlere bir destek olarak aktarmadan farklı şekillerde görüntülemesi gerekip gerekmediğini varsayalım. Reaksiyon bileşenlerinin dışında saklamak ideal olacaktır. Çünkü verileri farklı bileşenlere tamamen aktarmanız gerekmediğinden daha hızlı veri alımına yardımcı olur.

Redux ile bunun nasıl mümkün olduğunu tartışalım. Redux, react-redux paketini aşağıda belirtildiği gibi iki yardımcı programla react bileşenlerini bağlamak için sağlar -

  • Provider
  • Connect

Sağlayıcı, mağazayı uygulamanın geri kalanı için kullanılabilir hale getirir. Bağlan işlevi, mağazanın durumunda meydana gelen her değişikliğe yanıt vererek bileşenin mağazaya bağlanmasına yardımcı olur.

Bir göz atalım root index.js mağaza oluşturan ve bir react-redux uygulamasında mağazanın uygulamanın geri kalanına erişmesini sağlayan bir sağlayıcı kullanan dosya.

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux';
import reducer from './reducers/reducer'
import thunk from 'redux-thunk';
import App from './components/app'
import './index.css';

const store = createStore(
   reducer,
   window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
   applyMiddleware(thunk)
)
render(
   <Provider store = {store}>
      <App />
   </Provider>,
   document.getElementById('root')
)

Bir react-redux uygulamasında bir değişiklik meydana geldiğinde, mapStateToProps () çağrılır. Bu işlevde, react bileşenimize hangi durumu sağlamamız gerektiğini tam olarak belirtiriz.

Aşağıda açıklanan connect () fonksiyonunun yardımıyla, bu uygulamanın durumunu bileşen reaksiyona bağlayacağız. Connect (), bileşeni parametre olarak alan yüksek dereceli bir işlevdir. Belirli işlemleri gerçekleştirir ve sonunda dışa aktardığımız doğru verileri içeren yeni bir bileşen döndürür.

MapStateToProps () yardımıyla, bu mağaza durumlarını react bileşenimize destek olarak sunuyoruz. Bu kod, bir konteyner bileşenine sarılabilir. Bunun nedeni, veri getirme, endişe oluşturma ve yeniden kullanılabilirlik gibi endişeleri ayırmaktır.

import { connect } from 'react-redux'
import Listing from '../components/listing/Listing' //react component
import makeApiCall from '../services/services' //component to make api call

const mapStateToProps = (state) => {
   return {
      items: state.items,
      isLoading: state.isLoading
   };
};
const mapDispatchToProps = (dispatch) => {
   return {
      fetchData: () => dispatch(makeApiCall())
   };
};
export default connect(mapStateToProps, mapDispatchToProps)(Listing);

Services.js dosyasında api çağrısı yapmak için bir bileşenin tanımı aşağıdaki gibidir -

import axios from 'axios'
import { itemsLoading, itemsFetchDataSuccess } from '../actions/actions'

export default function makeApiCall() {
   return (dispatch) => {
      dispatch(itemsLoading(true));
      axios.get('http://api.tvmaze.com/shows')
      .then((response) => {
         if (response.status !== 200) {
            throw Error(response.statusText);
         }
         dispatch(itemsLoading(false));
         return response;
      })
      .then((response) => dispatch(itemsFetchDataSuccess(response.data)))
   };
}

mapDispatchToProps () işlevi, bir parametre olarak gönderme işlevini alır ve size react bileşeninize ilettiğiniz geri çağrı props'larını düz nesne olarak döndürür.

Burada, bir API çağrısı yapmak için bir eylem gönderen tepki listeleme bileşeninizde bir prop olarak fetchData'ya erişebilirsiniz. mapDispatchToProps (), depolanacak bir eylemi göndermek için kullanılır. React-redux'te, bileşenler mağazaya doğrudan erişemez. Bunun tek yolu connect () kullanmaktır.

React-redux'ün nasıl çalıştığını aşağıdaki diyagramdan anlayalım -

STORE - Tüm uygulama durumunuzu bir JavaScript nesnesi olarak depolar

PROVIDER - Mağazaları kullanılabilir hale getirir

CONTAINER - Uygulamaların durumunu alın ve bileşenlere destek olarak sağlayın

COMPONENT - Kullanıcı, görünüm bileşeni aracılığıyla etkileşim kurar

ACTIONS - Mağazada değişikliğe neden olur, uygulamanızın durumunu değiştirebilir veya değiştirmeyebilir

REDUCER - Uygulama durumunu değiştirmenin, durumu ve eylemi kabul etmenin ve güncellenmiş durumu döndürmenin tek yolu.

Ancak, Redux bağımsız bir kitaplıktır ve herhangi bir UI katmanıyla kullanılabilir. React-redux, resmi Redux, tepki ile UI bağlamasıdır. Dahası, iyi bir tepki veren Redux uygulama yapısını teşvik eder. React-redux, performans optimizasyonunu dahili olarak gerçekleştirir, böylece bileşen yeniden oluşturma işlemi yalnızca ihtiyaç duyulduğunda gerçekleşir.

Özetlemek gerekirse, Redux en kısa ve en hızlı kodu yazmak için tasarlanmamıştır. Öngörülebilir bir durum yönetimi kabı sağlaması amaçlanmıştır. Belirli bir durumun ne zaman değiştiğini veya verilerin nereden geldiğini anlamamıza yardımcı olur.

İşte react ve Redux uygulamasının küçük bir örneği. Küçük uygulamalar geliştirmeyi de deneyebilirsiniz. Artış veya azalış sayacı için örnek kod aşağıda verilmiştir -

Bu, mağazanın oluşturulmasından ve react uygulama bileşenimizin işlenmesinden sorumlu olan kök dosyadır.

/src/index.js

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux';
import reducer from '../src/reducer/index'
import App from '../src/App'
import './index.css';

const store = createStore(
   reducer,
   window.__REDUX_DEVTOOLS_EXTENSION__ && 
   window.__REDUX_DEVTOOLS_EXTENSION__()
)
render(
   <Provider store = {store}>
      <App />
   </Provider>, document.getElementById('root')
)

Bu bizim tepkimenin temel bileşenidir. Sayaç kapsayıcı bileşenini alt öğe olarak oluşturmaktan sorumludur.

/src/app.js

import React, { Component } from 'react';
import './App.css';
import Counter from '../src/container/appContainer';

class App extends Component {
   render() {
      return (
         <div className = "App">
            <header className = "App-header">
               <Counter/>
            </header>
         </div>
      );
   }
}
export default App;

Aşağıdakiler, Redux'un durumunun bileşene tepki vermesini sağlamaktan sorumlu olan konteyner bileşenidir -

/container/counterContainer.js

import { connect } from 'react-redux'
import Counter from '../component/counter'
import { increment, decrement, reset } from '../actions';

const mapStateToProps = (state) => {
   return {
      counter: state
   };
};
const mapDispatchToProps = (dispatch) => {
   return {
      increment: () => dispatch(increment()),
      decrement: () => dispatch(decrement()),
      reset: () => dispatch(reset())
   };
};
export default connect(mapStateToProps, mapDispatchToProps)(Counter);

Aşağıda, görünüm kısmından sorumlu reaksiyon bileşeni verilmiştir -

/component/counter.js
import React, { Component } from 'react';
class Counter extends Component {
   render() {
      const {counter,increment,decrement,reset} = this.props;
      return (
         <div className = "App">
            <div>{counter}</div>
            <div>
               <button onClick = {increment}>INCREMENT BY 1</button>
            </div>
            <div>
               <button onClick = {decrement}>DECREMENT BY 1</button>
            </div>
            <button onClick = {reset}>RESET</button>
         </div>
      );
   }
}
export default Counter;

Aşağıdakiler, bir eylem oluşturmaktan sorumlu eylem yaratıcılarıdır -

/actions/index.js
export function increment() {
   return {
      type: 'INCREMENT'
   }
}
export function decrement() {
   return {
      type: 'DECREMENT'
   }
}
export function reset() {
   return { type: 'RESET' }
}

Aşağıda, Redux'ta durumu güncellemekten sorumlu olan redüktör dosyası için kod satırını gösterdik.

reducer/index.js
const reducer = (state = 0, action) => {
   switch (action.type) {
      case 'INCREMENT': return state + 1
      case 'DECREMENT': return state - 1
      case 'RESET' : return 0 default: return state
   }
}
export default reducer;

Başlangıçta, uygulama aşağıdaki gibi görünür -

Artışı iki kez tıkladığımda, çıktı ekranı aşağıda gösterildiği gibi olacak -

Bir kez düşürdüğümüzde aşağıdaki ekranı gösterir -

Ve sıfırlama, uygulamayı sayaç değeri 0 olan başlangıç ​​durumuna geri götürür. Bu, aşağıda gösterilmektedir -

İlk artış eylemi gerçekleştiğinde Redux geliştirme araçlarıyla ne olduğunu anlayalım -

Uygulamanın durumu, yalnızca artırma eyleminin gönderildiği ve eylemlerin geri kalanının atlandığı zamana taşınacaktır.

Kendi başınıza bir ödev olarak küçük bir Todo Uygulaması geliştirmenizi ve Redux aracını daha iyi anlamanızı öneririz.