問題1:這個東西有什麼用,爲什麼要用它?
redux-observable 作爲redux 的一箇中間件提供了action 異步處理的能力,並且它基於RxJS,RxJS 是一個強大的庫,熟悉Angular 應該不會陌生。如果對RxJS 沒有興趣,那麼redux-observable 也沒必要去了解了。
爲什麼要用它呢?個人認爲:1 喜歡並熟悉RxJS,2 redux-observable 完全接管所有數據請求操作,通過 dispatch 指定action 進行異步數據步操作。也就是說大部分數據請求、數據的處理邏輯寫在redux-observable 的 epics中。這樣做有點類似angular 中的 【服務】 概念,簡單的說就是將業務邏輯和組件分離,組件只負責數據展示,至於數據如何處理怎麼來的不是組件應該關心的,組件只負責展示與收集數據。服務概念參見:https://www.angular.cn/guide/architecture-services 。
Angular 把組件和服務區分開,以提高模塊性和複用性。 通過把組件中和視圖有關的功能與其他類型的處理分離開,你可以讓組件類更加精簡、高效。
問題2: 說的天花亂墜各種好,怎麼用?
說到底,redux-observable 是redux 的一箇中間件,具體代碼和使用中間件是一樣的,如果熟悉redux 不難理解。epic 是redux-observable 中的一個概念,具體的定義參見官方文檔,簡單的說就是一個觸發器,它不會攔截 action action 會順利的抵達被reducer處理。當指定的一個或幾個action 被dispatch時 ,epic 進行異步的操作,比如去請求數據,當數據返回時,再dispatch 指定的action 去更新redux state。所以一個項目會有很多epic ,它有一個類似combineReducers 的方法 combineEpics 將衆多epic 合成一個rootEpic。combineEpics 和combineReducers 是有區別的它不能嵌套使用(ps:個人愚見,官網demo 沒看到像combineReducers 一樣的嵌套使用 )。
說了這麼多,epic 核心還是RxJS的使用,如果對RxJS 不熟悉建議還是去翻翻文檔吧。
正常的一個請求服務端數據的epic大致是這樣的。
- 發送數據前 一個loading 狀態
- 請求數據成功時 將數據處理完畢 更新redux state,有時一個請求可能要dispatch 多個action
- 可能會取消請求
- 請求數據錯誤(注意不是非200報錯)處理
- 請求報錯,可能是服務端報錯也可能是數據處理時報錯控制
- 請求完成時,去掉loading
官網還是有一些demo 的 但是不是很全,比如第2、1、4、6,
先貼代碼
import {of, concat} from 'rxjs';
import {mergeMap, map, catchError, finalize} from 'rxjs/operators';
import {ofType} from 'redux-observable';
import {FETCH_SUB_SITE_LIST, FETCH_MARKER_DATA, FETCH_OTHER_INFO, Actions} from "../redux/actions";
import {Ajax} from "../http.service";
import {message} from 'antd';
import {store} from "../redux";
export const getSubSiteListEpic = (action$: any, state$: any) => action$.pipe(
ofType(FETCH_SUB_SITE_LIST),
mergeMap((action) => {
const {value: {map: {main: {warehouseId}}}} = state$;
return concat(
of(Actions.updateLoadingStatus(true)),
Ajax.post('/api/getSubSiteList', {warehouseId}).pipe(
map(({response: {code, msg, data}}) => {
if (code !== 0) {
throw Error(msg);
}
const tempMap: any = {};
const temp = data.map((v: any) => {
tempMap[v.siteId] = v.districtList;
return {
label: v.siteName,
value: v.siteId
}
});
store.dispatch(Actions.updateDistrictMap(tempMap)); // 更新district 與子站映射
return Actions.updateSubSiteList(temp); // 更新子站列表
}),
catchError(({message: err}: any) => {
message.error(err);
return of(Actions.updateErrFetch(err))
}),
finalize(() => {
store.dispatch(Actions.updateLoadingStatus(false));
})
)
)
})
);
http.server.ts
export class Ajax {
static post(url: string, data?: any, method?: string) {
return race(
of({response:{code:408,msg:'請求超時!'}}).pipe(delay(50000)),
ajax.post(`${baseURL}${url}`, data, {
'Content-Type': 'application/json',
'token': sessionStorage.getItem('token')
}),
);
}
}
具體代碼參見:[email protected]:yyccmmkk/wms-map-react.git
具體RxJS API參見官方文檔。