關於 RxJS redux-observable

問題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大致是這樣的。

  1. 發送數據前 一個loading 狀態
  2. 請求數據成功時 將數據處理完畢 更新redux state,有時一個請求可能要dispatch 多個action
  3. 可能會取消請求
  4. 請求數據錯誤(注意不是非200報錯)處理
  5. 請求報錯,可能是服務端報錯也可能是數據處理時報錯控制
  6. 請求完成時,去掉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參見官方文檔。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章