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

通常在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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值