初识Redux-Saga
Redus-saga是一个redux的中间件,主要用来简便而优雅的处理redux应用里的副作用(side effect相对于pure function这类概念而言的)。它之所以可以做到这一点主要是使用了ES6里的一个语法:Generator。使用Generator可以像写同步的代码一样编写异步代码,这样更加容易测试。
在我们更深入之前,“saga”这个名字在计算机科学的历史上早已存在,并不是只用于javascript里的。Saga可以简要的概括为一种处理长时间运行的事务,并且这种事务会有副作用或者失败的可能。每一个我们希望完成的事务,都需要一个反事务在出错的时候把事务恢复到当前事务发生之前的样子。如果有兴趣了解更多Sage,我(作者)推荐你看看Caitie McCaffrey的这段演讲,演讲的题目是《实践Saga模式》。另外可以参阅Roman Liutikov的博客,叫做《Saga模式的迷惑之处》。
我们为什么要用Redux-saga
现在我们可以创建一个新的react-redux应用,我们会使用redux-thunk和redux-saga处理异步的action。所以我们为什么要用redux-saga呢?
正如文档里所说:
与redux-thunk相反,你不会跌入回调地狱,你可以很容易的测试你的异步流程而且action一直保持pure(纯的状态)。
我们来对比一下saga和thunk的用法来更深入的理解上面那句话的内容。假设场景为:用户点击按钮,发出一个http请求来获取数据。
Redux thunk的写法:
import {
API_BUTTON_CLICK,
API_BUTTON_CLICK_SUCCESS,
API_BUTTON_CLICK_ERROR,
} from './actions/consts';
import { getDataFromAPI } from './api';
const getDataStarted = () => ({type: API_BUTTON_CLICK});
const getDataSuccess = data => ({type: API_BUTTON_CLICK_SUCESS, payload: data});
const getDataError = message => ({type: API_BUTTON_CLICK_ERROR, payload: message});
const getDataFromAPI = () => {
return dispatch => {
dispatch(getDataStarted());
getDataFromAPI()
.then(data => {
dispatch(getUserSucess(data));
}).fail(err => {
dispatch(getDataError(err.message));
})
}
}
这里我们有一个叫做getDataFromAPI()的方法来创建action。当用户点击按钮开始了异步流程的时候“
- 首先触发一个action让我们的store知道我们要发起一个异步请求(
dispatch(getDataStarted())了。 - 接着我们实际发出了API请求,这个请求会返回一个promise。
- 然后我们会在成功接受到请求数据的时候触发成功的action,有错误的时候触发错误的action。
Redux saga的写法:
import { call, put, takeEvery } from 'redux-saga/effects';
import {
API_BUTTON_CLICK,
API_BUTTON_CLICK_SUCCESS,
API_BUTTON_CLICK_ERROR,
} from './actoins/consts';
import { getDataFromAPI } from './api';
export function* apiSideEffect(action) {
try{
const data = yield call(getDataFromaAPI);
yield put({ type: API_BUTTON_CLICK_SUCESS, payload: data});
} catch(e) {
yield put({type: API_BUTTON_CLICK_ERROR, payload: e.message});
}
}
// the 'watcher' -on every `API_BUTTON_CLICK` action, run our side effect
export function* apiSaga() {
yield takeEvery(API_BUTTON_CLICK, apiSideEffect);
}
流程基本上都是一样的,只是代码看起来略有不同:
- 与thunk例子不同的是,我们没有使用
dispatch而是用了put(我们可以认为两者是等价的)。 - 我们有一个监听方法一直监听着“start”方法。它只会在按钮点击之后触发一个类型为
API_BUTTON_CLICK的redux action。 - 我们用redux-saga的
calleffect(专有名词,效果的意思。与side effect的effect同意)来从异步的方法(promise,不同的saga等)里面获取数据。
非常简单,对吧。在某些按钮的点击事件里,我们会请求某些终端来获取数据。如果成功了,就发起一个新的,payload就是数据的action。否则就发出一个带有error消息的action。
同时,需要注意认真的理解上面的例子非常重要。不是说thunk的例子难以理解,但是我们却摆脱了返回方法或者promise链的麻烦。我们还可以只简单用一个try-catch来处理任何的异步错误。然后put(或者dispatch)一个action来通知reducer。
其次,更重要的是,我们的saga side effect(saga副作用)是纯的(pure)。这是因为call(getDataFromAPI)并不实际执行API请求,它只是返回一个纯对象:{type: 'CALL', func, args}。实际的请求已经由redux-saga中间件执行,并且会把返回值带到generator里(所以需要用yeild关键字)或者抛出一个异常,如果有的话。
掌握了以上概念以后,你就会明白下面的测试为什么这么简单:
import { call, put } from 'redux-saga/effects';
import { API_BUTTON_CLICK_SUCCESS, } from './actions/consts';
import { getDataFromAPI } from './api';
it('apiSideEffect - fetches data from API and dispatches a success action', () => {
const generator = apiSideEffect();
expect(generator.next().value).toEqual(call(getDataFromAPI));
expect(generator.next().value).toEqual(put({type: API_BUTTON_CLICK_SUCCESS }));
expect(generator.next()).toEqual({done: true, value: undefined});
});
然而上面的测试代码有一点点小问题。我们需要模拟getDataFromAPI方法的调用,其他在上面语句块的方法也需要模拟出来。这也许不是什么大的工作量,但是随着我们的action数量的增长,复杂度也会增加,类似上面的测试最好避免。
本文希望讲清楚redux-saga三个要点。我们不会再遇到回调地狱,我们的action是纯的,而且我们的异步流程很容易测试。如果你要学到更多,下面的资源会有帮助:
原文地址:https://engineering.universe.com/what-is-redux-saga-c1252fc2f4d1
初识Redux-Saga的更多相关文章
- [React] 14 - Redux: Redux Saga
Ref: Build Real App with React #14: Redux Saga Ref: 聊一聊 redux 异步流之 redux-saga [入门] Ref: 从redux-thun ...
- react系列(六)Redux Saga
在Redux中常要管理异步操作,目前社区流行的有Redux-Saga.Redux-thunk等.在管理复杂应用时,推荐使用Redux-Saga,它提供了用 generator 书写类同步代码的能力. ...
- react native redux saga增加日志功能
redux-logger地址:https://github.com/evgenyrodionov/redux-logger 目前Reac native项目中已经使用redux功能,异步中间件使用red ...
- redux+saga+reducer
saga.js这个文件里面的函数实际没有在其他jsx中引用吧?这个文件的作用就是把异步数据拿到,放进reducer,如果jsx想取,需要结合connect来取数据.
- 初识redux走向redux-react
废话不多说,先上一张图 首先记住redux设计思想 Web应用是一个转态机,视图与转态是一一对应的 所有的转态,保存在一个对象里 1.store 存储数据的容器,整个应用只有一个state,Redux ...
- 初识Redux Middleware
前言 原先改变store是通过dispatch(action) = > reducer:那Redux的Middleware是什么呢?就是dispatch(action) = > reduc ...
- redux saga学习
来源地址:https://www.youtube.com/watch?v=o3A9EvMspig Saga的基本写法 takeEvery与takeLatest的区别 takeEvery是指响应每一个请 ...
- [转] How to dispatch a Redux action with a timeout?
How to dispatch a Redux action with a timeout? Q I have an action that updates notification state of ...
- 《React与Redux开发实例精解》读书笔记
第五章 JSX语法 class属性改为className for属性改为htmlFor jsx中javascript表达式必须要有返回值,使用三元操作符 所有的标签必须闭合 input img等 re ...
随机推荐
- Python自学笔记-lambda函数(来自廖雪峰的官网Python3)
感觉廖雪峰的官网http://www.liaoxuefeng.com/里面的教程不错,所以学习一下,把需要复习的摘抄一下. 以下内容主要为了自己复习用,详细内容请登录廖雪峰的官网查看. 匿名函数 通过 ...
- Revit二次开发初体验
最近换了下工作,由之前的互联网企业转入了BIM软件开发行列.具体原因不多说,作为一个程序员来说学习永无止境.下面来一个Hello World体验下Revit的二次开发 事前准备 VS Revit 20 ...
- ubuntu的应用程序哪里找
一般来说11.04以前的桌面是gnome,点左上角的那个小圆圈,会出来一个下拉菜单,里面就有应用程序. 11.10以后的桌面换成unity 在dash中寻找应用程序很不方便,知道名字的还好,不知道名字 ...
- java web 学习笔记 编码问题总结
java web 学习笔记 编码问题总结 1.非form表单中提交的中文参数---------------------------传递给Servlet服务器时,默认以iso-8859-1解码 ...
- VUE长按事件
PS:在开发中常常会有长按事件的需求,这里我简单的介绍几种长按事件的需求 需求一:长按数字累加或者累减 HTML: <div class="mui-numbox" data- ...
- win10 uwp 列表模板选择器
本文主要讲ListView等列表可以根据内容不同,使用不同模板的列表模板选择器,DataTemplateSelector. 如果在 UWP 需要定义某些列的显示和其他列不同,或者某些行的显示和其他行不 ...
- spring框架应用系列一:annotation-config自动装配
本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7716678.html 解决问题 通过spring XML配置文件, ...
- Hadoop Streaming详解
一: Hadoop Streaming详解 1.Streaming的作用 Hadoop Streaming框架,最大的好处是,让任何语言编写的map, reduce程序能够在hadoop集群上运行:m ...
- Java基础总结--流程控制
Java流程控制* 顺序结构--最常见的执行情况,语句按照出现的先后次序依次执行.* 判断结构--对条件进行判断,执行相应的语句.有三种常见的形式< if(判断条件){语句;}--为真执行语句, ...
- vue数据请求
我是vue菜鸟,第一次用vue做项目,写一些自己的理解,可能有些不正确,欢迎纠正. vue开发环境要配置本地代理服务.把config文件加下的index.js里的dev添加一些内容, dev: { e ...