[译]在 Redux 中使用 AJAX 轮询(二):Saga 篇

不久以前我写了一篇关于在 React 中使用 AJAX 轮询的短文,内容能够归纳为如何发起和控制周期性 AJAX 请求。文中我证实了经过使用组件生命周期方法,原生 React 和 Redux 在技术上就足以解决 AJAX 轮询的控制问题。随着时间推移,在使用中我发现这个方法须要开发者很是细心地筛选和管理 componentWillReceiveProps 中传入的 props 。最终,个人目标变成了尽量地清除组件中的异步逻辑。html

在 Redux 生态中,已有很多管理反作用(side effect)的类库,从最基础的 redux-thunk,到受 Elm 熏陶的 redux-loop,最后还有使用 Generator 函数强力驱动的 redux-saga前端

理想状况下,我喜欢把全部的异步请求都放置到一个 API 中间件中,这种用法能够参考 Redux 官方实例 real-world example。若使用 thunk 会使个人 Action 建立函数被异步逻辑所污染,因此 redux-thunk 已然出局。使用 redux-loop 则会与个人中间件相冲突,做为 store 的一个 enhancer 它却修改了 store 的 signature,进而致使其下游的全部中间件都须要调整。因此综上我决定探索 redux-saga,它本质上提供给个人是在应用后台执行任务的能力。使用 redux-saga 能够保证我利用中间件集中控制异步逻辑的用法不变,同时经过设定各种不一样的观察者(watcher)来触发反作用。那么如何使用 redux-sage 处理 AJAX 轮询呢?react

// 延时反作用的工具函数
function delay(millis) {  
    const promise = new Promise(resolve => {
        setTimeout(() => resolve(true), millis)
    });
    return promise;
}

// 每隔 20 秒获取一次数据                                           
function* pollData() {  
    try {
        yield call(delay, 20000);
        yield put(dataFetch());
    } catch (error) {
        // 取消异常 -- 若是你愿意也能够捕获
        return;
    }
}

// 等待上一次数据请求返回成功后,发起下一轮轮询
// 若是用户登出,则取消本次未完成的轮询                                          
function* watchPollData() {  
    while (true) {             
        yield take(DATA_FETCH_SUCCESS);
        yield race([
            call(pollData),
            take(USER_LOGOUT)
        ]);
    }
}

// 让各种任务在后台并行运行                       
export default function* root() {  
    yield [
        fork(watchPollData)
        // 此处可包含其余观察者
    ];
}
复制代码

这种以 sagas 存在的轮询逻辑让开发者免于处理组件中潜在的复杂生命周期。我在 race 条件中添加了 USER_LOGOUT Action,这样能够代劳以前 componentWillUnmountclearTimeout 的工做。当发送 logout Action 后,运行中的 pollData saga 就能够被很好地中断执行。android

其他涉及到的逻辑以下:ios

dataFetch -- 它是一个 Action 建立函数,产生的 Action 会被 API 中间件拦截并处理。在中间件中会发起真正的 API 请求,并根据请求结果发出一系列后续 Action。git

watchPollData -- 它是一个随应用启动并一直运行的 saga。启动后它会阻塞 saga 执行并监听 DATA_FETCH_SUCCESS Action 的发出。一旦监听到相应的 Action 被发出,它就解除阻塞继续执行后续的 pollData saga。github

pollData -- 先阻塞 Generator 函数的执行,20秒后再调用 dataFetch 并 dispatch dataFetch 产生的 Action。ajax

此处用到的 takeputracecallfork 做用符,均可以在 redux-saga documentation 中找到。redux

你能够将本文的新方法与前一篇文章中在组件内作控制的方法做比较,使用 saga 后更利于预测和集中管理个人反作用。须要注意的是并非全部的浏览器都支持 Generator 函数,若是你使用了 ES2015 和 Babel,那么它们已经提供了 Generator 函数的浏览器 polyfill 兼容支持。后端

如今全部的数据容器(组件)只需在挂载的时候简单地调用一次 dataFetch() 便可,以后咱们的 saga 就会自动接管全部的轮询工做。很是简而美吧。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索