Redux - Middleware (3h)
Middleware
khá phổ biến với các Framework server-side, nó được đặt giữa thời điểm server nhận request và thời điểm server response. Ở Redux, Middleware giải quyết vấn đề khác với các Framework server-side nhưng định nghĩa có phần tương tự:
It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer.
Hiểu một cách đơn giản middleware cho phép chúng ta can thiệp vào giữa thời điểm dispatch một action và thời điểm action đến được reducer. Chúng ta có thể thấy sự thay đổi của flow khi có sử dụng middleware qua hình dưới:
Sử dụng Middleware¶
Để sử dụng được Middleware chúng ta cần sử dụng function applyMiddleware
của redux khi khởi tạo store
index.js
import { createStore, applyMiddleware } from 'redux';
import 'yourMiddleware' from 'your-middleware';
import rootReducer from './reducers/rootReducer';
const store = createStore(rootReducer, applyMiddleware(yourMiddleware));
Hiện nay redux đang có khá nhiều nhiều thư viện middleware bao gồm:
Redux-saga , redux-promise, redux-effects, redux-thunk, redux-connect, redux-loop, redux-side-effects, redux-logic, redux-observable, redux-ship
Nhưng nói chung trong đám kể trên thì chỉ có 3 cái tên xuất chúng nhất, được dùng phổ biến là:
Redux-Saga
Redux-Thunk
Redux-Observable
Ở đây chúng ta sẽ tìm hiểu về Redux-Observable
Redux-Observable¶
Giới thiệu¶
Redux Observable sử dụng RxJs và các đối tượng observable để tạo ra các tiến trình bất đồng bộ và luồng xử lý dữ liệu cho ứng dụng Redux.
Ứng dụng¶
https://drive.google.com/file/d/1S2AMpHwU5TqGkClytuIMm1KSfxnDb7PU/view?usp=sharing
Xem ví dụ sau, phát triển dựa theo bài trước:
Ở đây ta sẽ tạo một action getTemperature, có nhiệm vụ lấy nhiệt độ hiện tại. Để tiết kiệm thời gian viết api , ta sẽ fetch data từ một file .txt để đỡ tốn công viết api.
Tạo getResultEpic.js:
import {Observable} from 'rxjs';
import {GET_RESULT} from "../constants/ActionTypes";
import {getResultSuccess} from "../actions/GetResultActions";
import {combineEpics} from 'redux-observable';
/**
* Get result epic
* @param action$
* @returns {Observable<any>}
*/
function GetResultEpic(action$) {
return action$.ofType(GET_RESULT)
.mergeMap(action => Observable.from(
new Promise((resolve, reject) => {
/* fake to save time create api */
fetch(
'fakeresultapi.txt',
{
method: "GET",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
mode: 'cors'
}
).then(response => response.json()
.then(function (data) {
if (response.ok) {
return resolve(data);
} else {
return reject(data);
}
})
).catch(() => reject(''))
})
).mergeMap(
(response) => {
return [
getResultSuccess(response)
]
}
).catch(
() => {
return Observable.empty();
}
)
);
}
/**
*
*/
export const getResultEpic = combineEpics(
GetResultEpic,
);
export default getResultEpic;
Combine epic:
import {combineEpics} from 'redux-observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'
import getResultEpic from "./GetResultEpic";
export default () => {
const epic$ = new BehaviorSubject(combineEpics(
getResultEpic
));
const rootEpic = (action$, store) =>
epic$.mergeMap(epic =>
epic(action$, store)
);
return rootEpic
}
Đưa vào store:
Epic này sẽ chặn giữa khi action dispatch getResult và reducers, trước khi truyền vào reducer, ta sẽ fetch giá trị nhiệt độ. Sau khi có kết quả trả về, ta dispatch một action là getResultSuccess.
Get result success sẽ cập nhật lại state.