在redux-observable中替换fetch请求网络数据

来源:互联网 发布:c语言指向函数的指针 编辑:程序博客网 时间:2024/06/10 23:40

通常在React项目中会搭配redux来管理React的state状态. 由于项目有异步action的需求, 并且后续会使用到rxjs, 同时想要action层面保持良好的纯字面量风格, 这时就考虑使用redux-observable提供异步action的支持.

目前项目中用到异步action的场景主要是接口的请求, 在接入redux-observable之前项目是使用isomorphic-fetch来请求数据的, 接入中间件之后发现中间件本身的网络还是用的基于rxjs@5.x.x的ajax(XMLHttpRequest). 如果想用fetch来替换XMLHttpRequest在中间件中请求数据要怎么实现呢 ?

其实了解过fetch跟rxjs的特性的话应该会有思路. 首先中间件是通过执行Observable对象来支持异步aciton的, 其次fetch返回的是一个Promise对象, 而rxjs则可以把一个Promise对象包装成Observable对象. 那么我们按照这个套路把fetch包装到Observable对象里给epic方法使用是不是就能达到我们的目的了. 理论上来说是完全可行的, 那我们就以一个项目中的登录流程为例, 展示redux-observable + isomorphic-fetch的使用方式.

ACTION

因为使用了redux-observable中间件, 所以登录这个行为的action只是一个单纯的字面量. 发生登录行为时view直接dispatch该字面量就可以了.

/** * 登录action * @param account * @param pwd */export const loginAction = (account, pwd) => ({    type: ACTION_LOGIN,    data: {        account: account,        password: md5(pwd)    }});

代码跳转

Epic方法

在登录的epic方法中, 首先监听到action type为ACTION_LOGIN的分发, 然后按照中间件的特性将网络请求的结果封进一个新的action中, 再次分发出去. 这里将实现放入了一个工具方法中, 参数则是新action的type, 网络请求需要的相关数据等.

/** * 登录 epic * @param action$ */export const loginEpic = action$ =>    action$.ofType(ACTION_LOGIN)        .mergeMap(action => ajaxRequest({            actionType: ACTION_LOGIN_FULFILLED,            method: AJAX_METHOD.POST,            url: URL_LOGIN,            params: action.data        }));

代码跳转

ajaxRequest方法

在ajaxRequest方法中根据网络请求需要的参数构建出对应的Observable对象. 登录的调用是通过ajaxPost方法来构建的, 后面我们会说ajaxPost方法的实现. 当我们已经拿到Observable对象之后就要执行它并将结果或者异常以action的方式返回, 让epic方法重新dispatch出去.

/** * 提供给epic事件流使用, 根据参数构建request * @param requestParams {actionType, method, url, params} */export const ajaxRequest = requestParams => {    const {actionType, method, url, params} = requestParams;    let observable;    switch (method) {        case AJAX_METHOD.POST:            observable = ajaxPost(url, params);            break;        case AJAX_METHOD.GET:            observable = ajaxGet(url, params);            break;        case AJAX_METHOD.POST_FORM:            observable = ajaxPostForm(AJAX_METHOD.POST_FORM, url, params);            break;        case AJAX_METHOD.POST_MULTI_FORM:            observable = ajaxPostForm(AJAX_METHOD.POST_MULTI_FORM, url, params);            break;        default:            observable = ajaxGet(url, params);    }    return observable.map(data => ({        type: actionType,        data: data    })).catch(e => Observable.of({        type: actionType,        data: e    }));};

代码跳转

ajaxPost方法

ajaxPost很简单, 就是根据场景和isomorphic-fetch构建出application/json类型的post请求. 并将该fetch方法返回的Promise对象经过buildRequestObservable方法的包装封成Observable对象返回给ajaxRequest用.

/** * post请求json内容, 返回Observable promise 对象 * @param url * @param params * @returns {Observable.<T>|*} */export const ajaxPost = (url, params) => {    const content = JSON.stringify(params);    const data = {        method: AJAX_METHOD.POST,        headers: {            'Authorization': `Bearer ${localStorage.token}`,            "Content-Type": "application/json",            "Content-Length": content.length.toString()        },        body: content    };    return buildRequestObservable(fetch(url, data));};

代码跳转

buildRequestObservable方法

buildRequestObservable方法对参数中传递进来的fetch Promise对象进行拆解, 做一些公共处理, 然后重新打包成一个新的Promise对象. 如果请求成功则解析出正常的业务数据, 根据情况进行回调. 否则将请求失败和异常的情况包装到错误包中给reject出来. 最后通过rxjs的转换方法将新的Promise对象转化成Observable对象.

/** * 根据fetch promise对象构建出一个Observable * @param fetch * @returns {Observable<T>|*} */const buildRequestObservable = fetch => {    const request = new Promise((resolve, reject) => {        fetch.then((response) => {            if (!response.ok) {                reject(buildErrorInfo(RES_FAILED, 'response code error'));            }            response.json().then((data) => {                if (data.status === RES_SUCCEED) {                    resolve(data);                } else {                    reject(data)                }            });        }).catch((e) => {            reject(buildErrorInfo(RES_FAILED, e.toString()));        });    });    return Observable.fromPromise(request);};

代码跳转

到这里就成功在使用redux-observable时替换ajax(XMLHttpRequest)为isomorphic-fetch请求网络数据了. 由于我是对现有的系统进行进行改造的, 所以就没有用更加简单直接得代码Demo来展示, 顺便也分享一下这个CMS系统网络方面的设计, 同时也作为这个系统的文档之一. 项目Github地址: https://github.com/HiJesse/Demeter 欢迎交流.

转载请注明出处:http://blog.csdn.net/l2show/article/details/77444082

原创粉丝点击