首先,这个redux-saga和redux-thunk做的是同样的事情, 就是解决我们在redux中做异步的事情. 但 redux-saga 所涉及到的知识点和代码的复杂程度上都要复杂一些.
redux-saga 是基于ES6 的 Generator来实现的异步请求数据.
这是一个Generator例如:1
2
3
4function* g() {
var res = yield 1 + 2
return res
}
以上就是一个用同步方式来实现异步请求的Generator 函数. 更多的需要参考其文档. 这里就吧赘述了,因为我们的目的是记录学习 Redux-saga在react中的应用.
那么,我们如何使用Redux-saga来实现异步数据的交互呢? 这里我们列举一个完整的使用Reudx-saga来构建我们之前TodoList中数据获取部分的代码
首先,我们需要创建一个saga目录,用于存储我们的saga generator函数,具体代码内容贴如下:
1 | import { takeLatest, put, call, fork, all } from 'redux-saga/effects' |
注意, 我们这里所有的函数都是Generator函数, 并且我们使用了saga的内置辅助函数来协助我们实现异步.
我们可以注意到以上的getTodoList()函数,首先我们需要触发SHOW_LOADING的action来让列表显示一个加载状态, 然后我们使用了辅助函数call来调用执行我们的API接口函数,这个函数就是一个我们普通的
会返回一个Promise对象的HTTP函数.
我们看下api接口函数的定义:1
2
3
4
5import * as http from '../utils/http'
export async function fetchTodoList () {
return http.get('/getTodos')
}
非常简单, 很普通,这里不做过多说明了…
接着, 我们通过yield这个ES6的表达式让异步获取数据结束后,我们通过辅助函数put来执行下一个action,这里的put就好像redux本身的dispatch一样,是执行action的方法.
这样,我们就可以通过执行setTodo()这个action来执行其对应的reducer,继而更新state状态.
看到没, 我们并没有修改任何station, 也没有修改reducer. 我们这是在这里通过Generator函数异步执行了对应的action而已.
那么,继而有个问题出现, 就是saga怎么知道什么时候来执行这个Generator方法,然后触发更新呢?
接着,我们看刚才的第二段代码, 即 watchGetTodoList()函数. 这个里面用到了一个takeLatest辅助函数. 它的作用就是,不论你请求了多少次对应的action,我只取最后一次的数据. (注意,请求还是多次,并不会有debounce效果,谁让它不是RxJS呢 - -!).
OK,看代码, saga会监听我们的actions.GET_TODOS这个action,每当监听到我们执行了这个action,就会立即执行其第二个参数里的函数(必须是Generator).即我们代码里的getTodoList .
紧接着, 我们导出并执行我么的监控函数, 这里使用了fork辅助函数, 其和call使用的目的都是一样,区别就是fork是非阻塞的,call是阻塞的. 点这里看官方中文说明文档;
最后, 我们来修改一下index.js.
1 | import React from 'react'; |
以上是将前面咱们学的redux-thunk干掉了,换成了redux-saga .
我这里贴下action 是怎么写的. 其实是最原始的action,并没有任何特殊的地方, 我觉得就这点是让我最舒服的地方.我喜欢无侵入的设计
Action
1 | export const ADD_TODO = 'ADD_TODO' |
Redux-saga 的优势(自我感觉)
- 代码结构可以完全清晰的结构
- 不侵入现有的redux的action
- 构建在Generator之上,让异步函数写起来和同步函数别无二致
Redux-saga 的不足(XJB扯)
- 所需要的知识点过于繁杂,
- 虽然代码结构可以清晰,逻辑代码(非业务逻辑)不管会出现在Reducer中, 也会出现在saga里.
另外,想说的是, 对于redux-saga来说, 目前学习的仍然是皮毛,后续还可以再研究研究 :P.