问题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')
}),
);
}
}
具体代码参见:git@github.com:yyccmmkk/wms-map-react.git
具体RxJS API参见官方文档。