Redux - Panduan Cepat

Redux adalah wadah status yang dapat diprediksi untuk aplikasi JavaScript. Seiring pertumbuhan aplikasi, menjaganya menjadi sulit untuk tetap teratur dan mempertahankan aliran data. Redux memecahkan masalah ini dengan mengelola status aplikasi dengan satu objek global bernama Store. Prinsip dasar Redux membantu menjaga konsistensi di seluruh aplikasi Anda, yang membuat proses debug dan pengujian menjadi lebih mudah.

Lebih penting lagi, ini memberi Anda pengeditan kode langsung yang dikombinasikan dengan debugger perjalanan waktu. Ini fleksibel untuk digunakan dengan lapisan tampilan apa pun seperti React, Angular, Vue, dll.

Prinsip Redux

Prediktabilitas Redux ditentukan oleh tiga prinsip terpenting seperti yang diberikan di bawah ini -

Sumber Tunggal Kebenaran

Status seluruh aplikasi Anda disimpan dalam pohon objek dalam satu penyimpanan. Karena seluruh status aplikasi disimpan dalam satu pohon, hal itu membuat proses debug menjadi mudah, dan pengembangan lebih cepat.

Statusnya adalah Read-only

Satu-satunya cara untuk mengubah keadaan adalah dengan mengeluarkan tindakan, objek yang menjelaskan apa yang terjadi. Ini berarti tidak ada yang bisa langsung mengubah status aplikasi Anda.

Perubahan dilakukan dengan fungsi murni

Untuk menentukan bagaimana pohon negara diubah oleh tindakan, Anda menulis pereduksi murni. Peredam adalah tempat sentral di mana modifikasi negara berlangsung. Peredam adalah fungsi yang mengambil status dan tindakan sebagai argumen, dan mengembalikan status yang baru diperbarui.

Sebelum menginstal Redux, we have to install Nodejs and NPM. Di bawah ini adalah petunjuk yang akan membantu Anda menginstalnya. Anda dapat melewati langkah-langkah ini jika Anda sudah menginstal Nodejs dan NPM di perangkat Anda.

  • Mengunjungi https://nodejs.org/ dan instal file paket.

  • Jalankan penginstal, ikuti petunjuk dan terima perjanjian lisensi.

  • Mulai ulang perangkat Anda untuk menjalankannya.

  • Anda dapat memeriksa penginstalan yang berhasil dengan membuka command prompt dan mengetik node -v. Ini akan menunjukkan versi Node terbaru di sistem Anda.

  • Untuk memeriksa apakah npm telah berhasil diinstal, Anda dapat mengetik npm –v yang mengembalikan versi npm terbaru.

Untuk menginstal redux, Anda dapat mengikuti langkah-langkah di bawah ini -

Jalankan perintah berikut di command prompt Anda untuk menginstal Redux.

npm install --save redux

Untuk menggunakan Redux dengan aplikasi react, Anda perlu menginstal dependensi tambahan sebagai berikut -

npm install --save react-redux

Untuk menginstal alat pengembang untuk Redux, Anda perlu menginstal yang berikut ini sebagai dependensi -

Jalankan perintah di bawah ini di command prompt Anda untuk menginstal redux dev-tools.

npm install --save-dev redux-devtools

Jika Anda tidak ingin menginstal alat dev Redux dan mengintegrasikannya ke dalam proyek Anda, Anda dapat menginstal Redux DevTools Extension untuk Chrome dan Firefox.

Mari kita asumsikan status aplikasi kita dijelaskan oleh objek biasa yang disebut initialState yaitu sebagai berikut -

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

Setiap bagian kode dalam aplikasi Anda tidak dapat mengubah status ini. Untuk mengubah keadaan, Anda perlu mengirimkan tindakan.

Apa itu aksi?

Tindakan adalah objek biasa yang mendeskripsikan maksud untuk menyebabkan perubahan dengan properti tipe. Itu harus memiliki properti tipe yang memberi tahu jenis tindakan apa yang sedang dilakukan. Perintah untuk bertindak adalah sebagai berikut -

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

Tindakan dan status disatukan oleh fungsi yang disebut Peredam. Suatu tindakan dikirim dengan maksud untuk menyebabkan perubahan. Perubahan ini dilakukan oleh peredam. Reducer adalah satu-satunya cara untuk mengubah status di Redux, membuatnya lebih dapat diprediksi, terpusat, dan dapat di-debug. Fungsi peredam yang menangani tindakan 'ITEMS_REQUEST' adalah sebagai berikut -

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 memiliki satu toko yang menyimpan status aplikasi. Jika Anda ingin membagi kode Anda berdasarkan logika penanganan data, Anda harus mulai memisahkan reduksi daripada menyimpan di Redux.

Kami akan membahas bagaimana kami dapat membagi reduksi dan menggabungkannya dengan penyimpanan nanti di tutorial ini.

Komponen redux adalah sebagai berikut -

Reduks mengikuti aliran data searah. Artinya, data aplikasi Anda akan mengikuti aliran data binding satu arah. Seiring aplikasi berkembang & menjadi kompleks, sulit untuk mereproduksi masalah dan menambahkan fitur baru jika Anda tidak memiliki kendali atas status aplikasi Anda.

Redux mengurangi kompleksitas kode, dengan memberlakukan batasan tentang bagaimana dan kapan pembaruan status dapat terjadi. Dengan cara ini, mengelola status yang diperbarui itu mudah. Kita sudah tahu tentang pembatasan sebagai tiga prinsip Redux. Diagram berikut akan membantu Anda memahami aliran data Redux dengan lebih baik -

  • Suatu tindakan dikirim saat pengguna berinteraksi dengan aplikasi.

  • Fungsi peredam akar dipanggil dengan keadaan saat ini dan tindakan yang dikirim. Peredam akar dapat membagi tugas di antara fungsi peredam yang lebih kecil, yang pada akhirnya mengembalikan status baru.

  • Store memberi tahu tampilan dengan menjalankan fungsi panggilan baliknya.

  • Tampilan dapat mengambil status yang diperbarui dan merender ulang lagi.

Toko adalah pohon objek yang tidak dapat diubah di Redux. Penyimpanan adalah wadah negara yang menyimpan status aplikasi. Redux hanya dapat memiliki satu toko di aplikasi Anda. Setiap kali toko dibuat di Redux, Anda perlu menentukan peredamnya.

Mari kita lihat bagaimana kita bisa membuat toko menggunakan createStoremetode dari Redux. Satu kebutuhan untuk mengimpor paket createStore dari perpustakaan Redux yang mendukung proses pembuatan toko seperti yang ditunjukkan di bawah ini -

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

Fungsi createStore dapat memiliki tiga argumen. Berikut ini adalah sintaksnya -

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

Peredam adalah fungsi yang mengembalikan status aplikasi berikutnya. PreloadedState adalah argumen opsional dan merupakan status awal aplikasi Anda. Penambah juga merupakan argumen opsional. Ini akan membantu Anda meningkatkan toko dengan kemampuan pihak ketiga.

Sebuah toko memiliki tiga metode penting seperti yang diberikan di bawah ini -

getState

Ini membantu Anda mendapatkan kembali status penyimpanan Redux Anda saat ini.

Sintaks untuk getState adalah sebagai berikut -

store.getState()

pengiriman

Ini memungkinkan Anda mengirimkan tindakan untuk mengubah status dalam aplikasi Anda.

Sintaks untuk pengiriman adalah sebagai berikut -

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

langganan

Ini membantu Anda mendaftarkan panggilan balik yang akan dipanggil oleh toko Redux ketika suatu tindakan telah dikirim. Segera setelah status Redux diperbarui, tampilan akan dirender ulang secara otomatis.

Sintaks untuk pengiriman adalah sebagai berikut -

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

Perhatikan bahwa fungsi berlangganan mengembalikan fungsi untuk menghentikan langganan pendengar. Untuk berhenti berlangganan pendengar, kita dapat menggunakan kode di bawah ini -

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

Tindakan adalah satu-satunya sumber informasi untuk penyimpanan sesuai dokumentasi resmi Redux. Ini membawa muatan informasi dari aplikasi Anda ke toko.

Seperti yang dibahas sebelumnya, tindakan adalah objek JavaScript biasa yang harus memiliki atribut type untuk menunjukkan jenis tindakan yang dilakukan. Ini memberi tahu kita apa yang telah terjadi. Jenis harus didefinisikan sebagai konstanta string dalam aplikasi Anda seperti yang diberikan di bawah ini -

const ITEMS_REQUEST = 'ITEMS_REQUEST';

Terlepas dari atribut type ini, struktur objek tindakan sepenuhnya tergantung pada pengembang. Disarankan untuk menjaga objek tindakan Anda seringan mungkin dan hanya menyampaikan informasi yang diperlukan.

Untuk menyebabkan perubahan apa pun di toko, Anda perlu mengirimkan tindakan terlebih dahulu dengan menggunakan fungsi store.dispatch (). Objek tindakannya adalah sebagai berikut -

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

Pembuat Tindakan

Pencipta tindakan adalah fungsi yang merangkum proses pembuatan objek tindakan. Fungsi ini hanya mengembalikan objek Js biasa yang merupakan tindakan. Ini mempromosikan penulisan kode yang bersih dan membantu mencapai dapat digunakan kembali.

Mari kita belajar tentang pembuat tindakan yang memungkinkan Anda mengirimkan tindakan, ‘ITEMS_REQUEST’yang meminta data daftar item produk dari server. Sementara itu,isLoading status dibuat benar di peredam dalam jenis tindakan 'ITEMS_REQUEST' untuk menunjukkan bahwa item sedang dimuat, dan data masih belum diterima dari server.

Awalnya, status isLoading salah di initialStateobjek dengan asumsi tidak ada yang dimuat. Ketika data diterima di browser, status isLoading akan dikembalikan sebagai false dalam jenis tindakan 'ITEMS_REQUEST_SUCCESS' di peredam yang sesuai. Status ini dapat digunakan sebagai prop dalam komponen react untuk menampilkan loader / pesan di halaman Anda saat permintaan data aktif. Pencipta aksi adalah sebagai berikut -

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,
   }
}

Untuk menjalankan fungsi pengiriman, Anda perlu meneruskan tindakan sebagai argumen untuk fungsi pengiriman.

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

Anda dapat mengirimkan tindakan dengan langsung menggunakan store.dispatch (). Namun, kemungkinan besar Anda mengaksesnya dengan metode pembantu react-Redux yang dipanggilconnect(). Anda juga bisa menggunakanbindActionCreators() metode untuk mengikat banyak pembuat tindakan dengan fungsi pengiriman.

Fungsi adalah proses yang mengambil input yang disebut argumen, dan menghasilkan beberapa output yang disebut nilai kembali. Suatu fungsi disebut murni jika mematuhi aturan berikut -

  • Sebuah fungsi mengembalikan hasil yang sama untuk argumen yang sama.

  • Evaluasinya tidak memiliki efek samping, yaitu tidak mengubah data masukan.

  • Tidak ada mutasi variabel lokal & global.

  • Itu tidak tergantung pada keadaan eksternal seperti variabel global.

Mari kita ambil contoh sebuah fungsi yang mengembalikan dua kali nilai yang diteruskan sebagai input ke fungsi tersebut. Secara umum ditulis sebagai, f (x) => x * 2. Jika sebuah fungsi dipanggil dengan nilai argumen 2, maka outputnya adalah 4, f (2) => 4.

Mari kita tulis definisi fungsi dalam JavaScript seperti yang ditunjukkan di bawah ini -

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

Here, double is a pure function.

Sesuai dengan tiga prinsip di Redux, perubahan harus dilakukan dengan fungsi murni, yaitu peredam di Redux. Sekarang, pertanyaan muncul mengapa peredam harus merupakan fungsi murni.

Misalkan, Anda ingin mengirimkan tindakan yang tipenya adalah 'ADD_TO_CART_SUCCESS' untuk menambahkan item ke aplikasi keranjang belanja Anda dengan mengklik tombol tambahkan ke keranjang.

Mari kita asumsikan peredam menambahkan item ke keranjang Anda seperti yang diberikan di bawah ini -

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 ;

Mari kita anggap, isAddedToCart adalah properti pada objek status yang memungkinkan Anda memutuskan kapan menonaktifkan tombol 'tambahkan ke keranjang' untuk item tersebut dengan mengembalikan nilai Boolean ‘true or false’. Ini mencegah pengguna untuk menambahkan produk yang sama beberapa kali. Sekarang, alih-alih mengembalikan objek baru, kami memutasi prop isAddedToCart pada status seperti di atas. Sekarang jika kami mencoba menambahkan item ke keranjang, tidak ada yang terjadi. Tombol Tambahkan ke keranjang tidak akan dinonaktifkan.

Alasan perilaku ini adalah sebagai berikut -

Redux membandingkan objek lama dan baru dengan lokasi memori kedua objek tersebut. Ia mengharapkan objek baru dari peredam jika ada perubahan yang terjadi. Dan itu juga mengharapkan untuk mendapatkan kembali objek lama jika tidak ada perubahan yang terjadi. Dalam hal ini, sama saja. Karena alasan ini, Redux berasumsi bahwa tidak ada yang terjadi.

Jadi, peredam perlu menjadi fungsi murni di Redux. Berikut ini adalah cara menulisnya tanpa mutasi -

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;

Pereduksi adalah fungsi murni di Redux. Fungsi murni dapat diprediksi. Pengecil adalah satu-satunya cara untuk mengubah status di Redux. Ini adalah satu-satunya tempat di mana Anda dapat menulis logika dan perhitungan. Fungsi peredam akan menerima status aplikasi dan tindakan sebelumnya yang dikirim, menghitung status berikutnya dan mengembalikan objek baru.

Beberapa hal berikut tidak boleh dilakukan di dalam peredam -

  • Mutasi argumen fungsi
  • Panggilan API & logika perutean
  • Memanggil fungsi non-murni misalnya Math.random ()

Berikut ini adalah sintaks peredam -

(state,action) => newState

Mari kita lanjutkan contoh menampilkan daftar item produk di halaman web, yang dibahas dalam modul pembuat tindakan. Mari kita lihat di bawah ini cara menulis peredamnya.

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;

Pertama, jika Anda tidak menyetel status ke 'initialState', Redux memanggil peredam dengan status tidak ditentukan. Dalam contoh kode ini, fungsi concat () dari JavaScript digunakan di 'ITEMS_REQUEST_SUCCESS', yang tidak mengubah larik yang ada; sebagai gantinya mengembalikan array baru.

Dengan cara ini, Anda dapat menghindari mutasi keadaan. Jangan pernah menulis langsung ke negara. Di 'ITEMS_REQUEST', kita harus menyetel nilai status dari tindakan yang diterima.

Telah dibahas bahwa kita dapat menulis logika kita di reducer dan dapat membaginya berdasarkan data logis. Mari kita lihat bagaimana kita dapat memisahkan reducer dan menggabungkannya sebagai root reducer saat menangani aplikasi besar.

Misalkan, kita ingin mendesain halaman web di mana pengguna dapat mengakses status pesanan produk dan melihat informasi daftar keinginan. Kami dapat memisahkan logika dalam file reduksi yang berbeda, dan membuatnya bekerja secara independen. Mari kita asumsikan bahwa tindakan GET_ORDER_STATUS dikirim untuk mendapatkan status pesanan yang sesuai dengan beberapa id pesanan dan id pengguna.

/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;
   }
}

Demikian pula, asumsikan tindakan GET_WISHLIST_ITEMS dikirim untuk mendapatkan informasi daftar keinginan pengguna masing-masing dari pengguna.

/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;
   }
}

Sekarang, kita dapat menggabungkan kedua reduksi dengan menggunakan utilitas Redux CombineReducers. CombineReducers menghasilkan fungsi yang mengembalikan objek yang nilainya merupakan fungsi peredam yang berbeda. Anda dapat mengimpor semua reduksi dalam file peredam indeks dan menggabungkannya bersama sebagai objek dengan namanya masing-masing.

/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;

Sekarang, Anda dapat meneruskan rootReducer ini ke metode createStore sebagai berikut -

const store = createStore(rootReducer);

Redux sendiri sinkron, jadi bagaimana async operasi seperti network requestbekerja dengan Redux? Di sini middlewares berguna. Seperti yang telah dibahas sebelumnya, reduksi adalah tempat di mana semua logika eksekusi ditulis. Reducer tidak ada hubungannya dengan siapa yang melakukannya, berapa lama waktu yang dibutuhkan, atau mencatat status aplikasi sebelum dan sesudah tindakan dikirim.

Dalam hal ini, fungsi middleware Redux menyediakan media untuk berinteraksi dengan tindakan yang dikirim sebelum mencapai peredam. Fungsi middleware yang disesuaikan dapat dibuat dengan menulis fungsi urutan tinggi (fungsi yang mengembalikan fungsi lain), yang membungkus beberapa logika. Beberapa middleware dapat digabungkan untuk menambahkan fungsionalitas baru, dan setiap middleware tidak memerlukan pengetahuan tentang apa yang datang sebelum dan sesudah. Anda dapat membayangkan middlewares di suatu tempat antara tindakan yang dikirim dan peredam.

Biasanya, middlewares digunakan untuk menangani tindakan asinkron di aplikasi Anda. Redux menyediakan API yang disebut applyMiddleware yang memungkinkan kita untuk menggunakan middleware kustom serta middleware Redux seperti redux-thunk dan redux-promise. Ini berlaku middlewares untuk menyimpan. Sintaks menggunakan API applyMiddleware adalah -

applyMiddleware(...middleware)

Dan ini dapat diterapkan ke toko sebagai berikut -

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

Middlewares akan membiarkan Anda menulis dispatcher tindakan yang mengembalikan fungsi alih-alih objek tindakan. Contoh yang sama ditunjukkan di bawah ini -

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

Pengiriman bersyarat dapat ditulis di dalam middleware. Setiap middleware menerima pengiriman toko sehingga mereka dapat mengirimkan tindakan baru, dan fungsi getState sebagai argumen sehingga mereka dapat mengakses status saat ini dan mengembalikan fungsi. Setiap nilai kembali dari fungsi dalam akan tersedia sebagai nilai fungsi pengiriman itu sendiri.

Berikut ini adalah sintaks middleware -

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

Fungsi getState berguna untuk memutuskan apakah data baru akan diambil atau hasil cache harus dikembalikan, bergantung pada status saat ini.

Mari kita lihat contoh fungsi logger middleware kustom. Ini hanya mencatat tindakan dan status baru.

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;
   }
}

Sekarang terapkan middleware logger ke toko dengan menulis baris kode berikut -

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

Kirim tindakan untuk memeriksa tindakan yang dikirim dan status baru menggunakan kode di bawah ini -

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

Contoh lain dari middleware di mana Anda dapat menangani kapan harus menampilkan atau menyembunyikan loader diberikan di bawah ini. Middleware ini menampilkan loader ketika Anda meminta sumber daya apa pun dan menyembunyikannya ketika permintaan sumber daya telah selesai.

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 memberi kami platform debugging untuk aplikasi Redux. Ini memungkinkan kami untuk melakukan debugging perjalanan waktu dan pengeditan langsung. Beberapa fitur dalam dokumentasi resmi adalah sebagai berikut -

  • Ini memungkinkan Anda memeriksa setiap muatan status dan tindakan.

  • Ini memungkinkan Anda kembali ke masa lalu dengan tindakan "membatalkan".

  • Jika Anda mengubah kode peredam, setiap tindakan "bertahap" akan dievaluasi ulang.

  • Jika reduksi melempar, kita dapat mengidentifikasi kesalahan dan juga selama tindakan apa ini terjadi.

  • Dengan penyempurna penyimpanan persistState (), Anda bisa mempertahankan sesi debug di seluruh pemuatan ulang halaman.

Ada dua varian dev-tools Redux seperti yang diberikan di bawah ini -

Redux DevTools - Ini dapat diinstal sebagai paket dan diintegrasikan ke dalam aplikasi Anda seperti yang diberikan di bawah ini -

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

Redux DevTools Extension - Ekstensi browser yang menerapkan alat pengembang yang sama untuk Redux adalah sebagai berikut -

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

Sekarang mari kita periksa bagaimana kita dapat melewati tindakan dan kembali ke masa lalu dengan bantuan alat pengembang Redux. Screenshot berikut menjelaskan tentang tindakan yang telah kami kirim sebelumnya untuk mendapatkan daftar item. Di sini kita dapat melihat tindakan yang dikirim di tab inspektur. Di sebelah kanan, Anda dapat melihat tab Demo yang menunjukkan perbedaan pohon negara.

Anda akan terbiasa dengan alat ini saat Anda mulai menggunakannya. Anda dapat mengirimkan tindakan tanpa menulis kode sebenarnya hanya dari alat plugin Redux ini. Opsi Dispatcher di baris terakhir akan membantu Anda dalam hal ini. Mari kita periksa tindakan terakhir di mana item berhasil diambil.

Kami menerima berbagai objek sebagai respons dari server. Semua data tersedia untuk menampilkan daftar di halaman kami. Anda juga dapat melacak status toko pada saat yang sama dengan mengklik tab status di sisi kanan atas.

Di bagian sebelumnya, kita telah mempelajari tentang proses debug perjalanan waktu. Sekarang mari kita periksa cara melewatkan satu tindakan dan kembali ke masa lalu untuk menganalisis status aplikasi kita. Saat Anda mengklik jenis tindakan apa pun, dua opsi: 'Lompat' dan 'Lewati' akan muncul.

Dengan mengklik tombol lewati pada jenis tindakan tertentu, Anda dapat melewati tindakan tertentu. Bertindak seolah-olah tindakan itu tidak pernah terjadi. Saat Anda mengklik tombol lompat pada jenis tindakan tertentu, Anda akan dibawa ke status saat tindakan itu terjadi dan melewati semua tindakan yang tersisa secara berurutan. Dengan cara ini Anda akan dapat mempertahankan status saat tindakan tertentu terjadi. Fitur ini berguna dalam men-debug dan menemukan kesalahan dalam aplikasi.

Kami melewatkan tindakan terakhir, dan semua data daftar dari latar belakang lenyap. Dibutuhkan kembali ke waktu ketika data item belum sampai, dan aplikasi kita tidak memiliki data untuk dirender di halaman. Itu sebenarnya membuat pengkodean menjadi mudah dan debugging lebih mudah.

Menguji kode Redux itu mudah karena kami kebanyakan menulis fungsi, dan kebanyakan dari mereka murni. Jadi kita bisa mengujinya tanpa mengejek mereka. Di sini, kami menggunakan JEST sebagai mesin penguji. Ia bekerja di lingkungan node dan tidak mengakses DOM.

Kita dapat menginstal JEST dengan kode yang diberikan di bawah ini -

npm install --save-dev jest

Dengan babel, Anda perlu menginstal babel-jest sebagai berikut -

npm install --save-dev babel-jest

Dan konfigurasikan untuk menggunakan fitur babel-preset-env di file .babelrc sebagai berikut -

{ 
   "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 
}

Akhirnya, run npm test or npm run test. Mari kita periksa bagaimana kita dapat menulis kasus uji untuk pembuat dan pereduksi tindakan.

Uji Kasus untuk Pembuat Tindakan

Mari kita asumsikan Anda memiliki pembuat aksi seperti yang ditunjukkan di bawah ini -

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

Pencipta tindakan ini dapat diuji seperti yang diberikan di bawah ini -

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) 
   })
})

Uji Kasus untuk Pereduksi

Kami telah mempelajari bahwa peredam harus mengembalikan keadaan baru ketika tindakan diterapkan. Jadi peredam diuji pada perilaku ini.

Pertimbangkan peredam seperti yang diberikan di bawah ini -

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;

Untuk menguji peredam di atas, kita perlu meneruskan status dan tindakan ke peredam, dan mengembalikan keadaan baru seperti yang ditunjukkan di bawah ini -

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
      })
   })
})

Jika Anda tidak terbiasa menulis test case, Anda dapat memeriksa dasar-dasar JEST .

Di bab-bab sebelumnya, kita telah mempelajari apa itu Redux dan cara kerjanya. Sekarang mari kita periksa integrasi bagian tampilan dengan Redux. Anda dapat menambahkan lapisan tampilan apa pun ke Redux. Kami juga akan membahas perpustakaan react dan Redux.

Katakanlah jika berbagai komponen react perlu menampilkan data yang sama dengan cara berbeda tanpa meneruskannya sebagai prop ke semua komponen dari komponen tingkat atas ke bawah. Akan sangat ideal untuk menyimpannya di luar komponen react. Karena ini membantu pengambilan data lebih cepat karena Anda tidak perlu meneruskan data sepenuhnya ke berbagai komponen.

Mari kita bahas bagaimana mungkin dengan Redux. Redux menyediakan paket react-redux untuk mengikat komponen react dengan dua utilitas seperti yang diberikan di bawah ini -

  • Provider
  • Connect

Penyedia membuat toko tersedia untuk aplikasi lainnya. Fungsi Connect membantu bereaksi komponen untuk menghubungkan ke toko, menanggapi setiap perubahan yang terjadi di negara bagian toko.

Mari kita lihat root index.js file yang membuat penyimpanan dan menggunakan penyedia yang memungkinkan penyimpanan ke seluruh aplikasi dalam aplikasi react-redux.

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')
)

Setiap kali perubahan terjadi dalam aplikasi react-redux, mapStateToProps () dipanggil. Dalam fungsi ini, kami secara tepat menentukan status mana yang perlu kami sediakan untuk komponen react kami.

Dengan bantuan fungsi connect () yang dijelaskan di bawah ini, kami menghubungkan status aplikasi ini untuk mereaksi komponen. Connect () adalah fungsi orde tinggi yang mengambil komponen sebagai parameter. Ini melakukan operasi tertentu dan mengembalikan komponen baru dengan data yang benar yang akhirnya kami ekspor.

Dengan bantuan mapStateToProps (), kami menyediakan status penyimpanan ini sebagai prop untuk komponen react kami. Kode ini dapat dibungkus dalam komponen kontainer. Motifnya adalah untuk memisahkan masalah seperti pengambilan data, memberikan kekhawatiran, dan dapat digunakan kembali.

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);

Definisi komponen untuk membuat panggilan api di file services.js adalah sebagai berikut -

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)))
   };
}

Fungsi mapDispatchToProps () menerima fungsi pengiriman sebagai parameter dan mengembalikan Anda callback props sebagai objek biasa yang Anda teruskan ke komponen react Anda.

Di sini, Anda dapat mengakses fetchData sebagai prop di komponen daftar reaksi Anda, yang mengirimkan tindakan untuk membuat panggilan API. mapDispatchToProps () digunakan untuk mengirimkan tindakan untuk disimpan. Dalam react-redux, komponen tidak dapat mengakses penyimpanan secara langsung. Satu-satunya cara adalah dengan menggunakan connect ().

Mari kita pahami cara kerja react-redux melalui diagram di bawah ini -

STORE - Menyimpan semua status aplikasi Anda sebagai objek JavaScript

PROVIDER - Membuat toko tersedia

CONTAINER - Dapatkan status aplikasi & berikan sebagai penyangga komponen

COMPONENT - Pengguna berinteraksi melalui komponen tampilan

ACTIONS - Menyebabkan perubahan di toko, mungkin atau mungkin tidak mengubah status aplikasi Anda

REDUCER - Satu-satunya cara untuk mengubah status aplikasi, menerima status dan tindakan, dan mengembalikan status yang diperbarui.

Namun, Redux adalah pustaka independen dan dapat digunakan dengan lapisan UI apa pun. React-redux adalah Redux resmi, UI mengikat dengan react. Selain itu, ini mendorong struktur aplikasi Redux bereaksi yang baik. React-redux secara internal mengimplementasikan pengoptimalan kinerja, sehingga rendering ulang komponen hanya terjadi jika diperlukan.

Singkatnya, Redux tidak dirancang untuk menulis kode terpendek dan tercepat. Ini dimaksudkan untuk menyediakan wadah pengelolaan keadaan yang dapat diprediksi. Ini membantu kami memahami kapan keadaan tertentu berubah, atau dari mana data berasal.

Berikut adalah contoh kecil dari react dan aplikasi Redux. Anda juga dapat mencoba mengembangkan aplikasi kecil. Kode contoh untuk penghitung kenaikan atau penurunan diberikan di bawah ini -

Ini adalah file root yang bertanggung jawab untuk pembuatan store dan rendering komponen aplikasi react kita.

/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')
)

Ini adalah komponen utama dari react. Ini bertanggung jawab untuk merender komponen kontainer counter sebagai anak.

/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;

Berikut ini adalah komponen wadah yang bertanggung jawab untuk menyediakan status Redux untuk bereaksi komponen -

/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);

Diberikan di bawah ini adalah komponen react yang bertanggung jawab untuk bagian tampilan -

/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;

Berikut ini adalah pembuat tindakan yang bertanggung jawab untuk membuat tindakan -

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

Di bawah ini, kami telah menunjukkan baris kode untuk file peredam yang bertanggung jawab untuk memperbarui status di Redux.

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;

Awalnya, aplikasi terlihat sebagai berikut -

Ketika saya mengklik kenaikan dua kali, layar output akan seperti yang ditunjukkan di bawah ini -

Ketika kami mengurangi sekali, itu menunjukkan layar berikut -

Dan reset akan membawa aplikasi kembali ke keadaan awal yaitu nilai counter 0. Ini ditunjukkan di bawah -

Mari kita pahami apa yang terjadi dengan alat dev Redux ketika tindakan kenaikan pertama terjadi -

Status aplikasi akan dipindahkan ke waktu ketika hanya tindakan kenaikan yang dikirim dan tindakan lainnya dilewati.

Kami mendorong untuk mengembangkan Aplikasi Todo kecil sebagai tugas sendiri dan memahami alat Redux dengan lebih baik.