博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redux-saga-整理
阅读量:7158 次
发布时间:2019-06-29

本文共 5230 字,大约阅读时间需要 17 分钟。

介绍

  1. 在redux中更好的解决异步操作
  2. redux-saga相当于在redux原来的数据流中多了一层,对action进行监听
  3. 接收到action时,派发一个任务维护state
  4. saga通过Generator方式创建,异步方法同步化

正常redux流程

f25a9bb7438d6d66759dacb2c37b25d384e9cecb

加入redux-saga之后的流程

c4df9e106a2b46030b1c9637071bacf9fb68ce59

使用方式

import { createStore, applyMiddleware } from 'redux'import createSagaMiddleware from 'redux-saga'//引入saga文件import { rootSaga } from './rootSaga'//使用 redux-saga 模块的 createSagaMiddleware 工厂函数来创建一个 Saga middleware。//运行 rootSaga 之前,我们必须使用 applyMiddleware 将 middleware 连接至 Store。然后使用 const sagaMiddleware = createSagaMiddleware();const middlewares = [ sagaMiddleware ];const store = createStore(rootReducer, applyMiddleware(...middlewares));sagaMiddleware.run(rootSaga);

redux-saga 辅助函数

sage提供了一些辅助函数,包装了一些内部方法,用来在一些特定的action被发起到store时派生任务

takeEvery

import { call, put } from 'redux-saga/effects'export function* fetchData(action) {   try {      const data = yield call(Api.fetchUser, action.payload.url);      yield put({type: "FETCH_SUCCEEDED", data});   } catch (error) {      yield put({type: "FETCH_FAILED", error});   }}function* watchFetchData() {  yield* takeEvery('FETCH_REQUESTED', fetchData)}//有一种用法:监控所有的发起的actionyield takeEvery('*', fn)

takeEvery 允许多个 fetchData 实例同时启动, 在某个特定时刻, 尽管之前还有一个或多个fetchData尚未结束, 我们还是可以启动一个新的fetchData任务-->意思就是只用调用了 FETCH_REQUESTED action的时候就会启动 fetchData 任务.

takeLatest

function* watchFetchData() {  yield* takeLatest('FETCH_REQUESTED', fetchData)}

在任何时刻 takeLatest只允许一个 fetchData 任务在执行,并且这个任务是最后被启动的那个,如果之前有一个任务再启动的时候执行了fetchData , 那么之前的任务会被自动取消 -- 可以获得最后一次(最新)调用FETCH_REQUESTED action 得到的结果.


Effects

概念

sagas都是Generator函数实现,可以用yield 对 js 对象来表达saga的逻辑,这些对象就是effect,

sagas都是用Generator函数实现的 在 Generator 函数中,yield 右边的任何表达式都会被求值,结果会被 yield 给调用者 用yield对Effect(简单对象),进行解释执行 Effect 是一个简单的对象,这个对象包含了一些
给 middleware 解释执行的信息。 你可以把 Effect 看作是发送给 middleware 的指令以执行某些操作(调用某些异步函数,发起一个 action 到 store,等等)
//官方例子import { takeEvery } from 'redux-saga/effects'import Api from './path/to/api'//监听如果有一个调用PRODUCTS_REQUESTED 的action的话,就会匹配到第二个参数所代表的effectfunction* watchFetchProducts() {  yield takeEvery('PRODUCTS_REQUESTED', fetchProducts)}//执行,获取数据//使用Generator 调用了Api.fetch,在Generator函数中,yield右面的任何表达式都会被求值,结果会被yield给调用者function* fetchProducts() {  const products = yield Api.fetch('/products')  console.log(products)}//第二种方式import { call } from 'redux-saga/effects'//call(fn, ...args) 这个函数。与前面的例子不同的是,现在我们不立即执行异步调用,相反,call//创建了一条描述结果的信息就像在 Redux 里你使用 action 创建器,创建一个将被 Store 执行的、描述 action 的纯文本对象。//call 创建一个纯文本对象描述函数调用。redux-saga middleware 确保执行函数调用并在响应被 resolve 时恢复 generatorfunction* fetchProducts() {  const products = yield call(Api.fetch, '/products')  // ...}

发送action到store

//这种方式是Generator获取到了返回值,在调用dispatchfunction* fetchProducts(dispatch)  const products = yield call(Api.fetch, '/products')  dispatch({ type: 'PRODUCTS_RECEIVED', products })}import { call, put } from 'redux-saga/effects'//...function* fetchProducts() {  const products = yield call(Api.fetch, '/products')  // 创建并 yield 一个 dispatch Effect  yield put({ type: 'PRODUCTS_RECEIVED', products })}

错误处理

import Api from './path/to/api'import { call, put } from 'redux-saga/effects'function* fetchProducts() {  try {    const products = yield call(Api.fetch, '/products')    yield put({ type: 'PRODUCTS_RECEIVED', products })  }  catch(error) {    yield put({ type: 'PRODUCTS_REQUEST_FAILED', error })  }}

使用 try/catch 的方式捕获saga的错误信息


一些概念

从 Saga 内触发异步操作(Side Effect)总是由 yield 一些声明式的 Effect 来完成的 , 一个 Saga 所做的实际上是组合那些所有的 Effect,共同实现所需的控制流。使用上是用yield Effects的方式来完成,Effect包括

  1. call: yield call(Generator, param) yield一个call,命令middleware以参数param调用函数 到Generator,saga等待Generator执行之后,接收返回值继续执行,call是堵塞的,就是等待执行完再继续执行,返回的是执行完正常返回的结果.
  2. take: 是阻塞的,只有监听到他(action.type),才会继续往下执行.也就是说创建一个effect的描述信息,用来命令middleware在Store上等待指定action,在发起与他相匹配的action之前,Generator将暂停.
  3. put: 类似dispatch方法,触发一个action,用来命令middleware向Store发起一个action请求,而且是非阻塞的
  4. fork: 非阻塞的,遇到它不需要等待他执行完毕,就可以继续往下执行,fork返回的是一个任务,可以被取消
  5. cancel: 针对fork方法返回的任务,进行取消
  6. select: 可以从全局state中获取状态
  7. saga: 就是用* 注册的函数,一个函数就是一个saga
  8. effect: 上面的call,put,take...就是effect
function* watchAndLog() {  while (true) {    const action = yield take('*')    const state = yield select()  }}take,它将会暂停 Generator 直到一个匹配的 action 被发起了,watchAndLog 处于暂停状态,直到任意的一个 action 被发起。

无阻塞调用-fork

fork一个任务,任务会在后台启动,调用者也可以继续它的流程,而不用等待被fork的任务执行结束 当我们需要有并发操作的时候,使用call effect会阻塞saga的执行,使用fork就需要关心被阻塞,或者等待结果返回在继续执行

const result = yield fork (saga,param)

同时执行多个任务

const [users, repos] = yield [  call(fetch, '/users'),  call(fetch, '/repos')]

当需要同步执行多个任务,需要把yield一个包含了effect的数组,Generator将会阻塞,等所有的effect都执行完毕


使用

//redux.connect所需要绑定到props上的actionfunction mapDispatchToProps(dispatch) {    return {        getHome: bindActionCreators(getHomeAdData, dispatch)    }}//一个 action creatorexport function getHomeAdData(){    return {        type: actionTypes.HOME_AD_DATA,    }}//监听action.type,然后出发后面的actionexport default function* rootSaga () {    // 就在这个rootSaga里面利用takeEvery去监听action的type    yield takeEvery('HOME_AD_DATA', getHomeAdData);    yield takeEvery('GET_LIKE_LIST_DATA', getLikeListData);}//通过yield call Effect 获取返回值,继续下面操作export function* getHomeAdData() {    let data = yield call(getAdData)    ...    yield put({type:UPDATE_HOME_AD_DATA, data: dataArr})}export function getAdData() {    const result = axios.get('/api/homead')    return result}
原文发布时间为:2018年06月025日

原文作者:
mazy
本文来源: 
 
如需转载请联系原作者
你可能感兴趣的文章
Rails中的约定与命名规范
查看>>
java学习路径
查看>>
Centos 7安装和配置 ElasticSearch入门小白
查看>>
苹果第三财季表现超预期 市值接近1万亿美元
查看>>
推荐 :数据科学部门如何建立
查看>>
Arm linux 内核构建
查看>>
android网络上传图片数据到服务端
查看>>
百度测试开发岗位面试题目
查看>>
Spring Cloud(四)服务提供者 Eureka + 服务消费者 Feign
查看>>
Spring-Data-Jpa的使用
查看>>
CentOS7安装软件报错:Cannot allocate memory
查看>>
HttpClient上传文件到微信素材乱码问题解决
查看>>
主动模式和被动模式
查看>>
分类、回归
查看>>
Dubbo源码阅读笔记(一)
查看>>
List跟踪源码个人记录
查看>>
企业级 SpringCloud 教程 (七)高可用的分布式配置中心(Spring Cloud Config)
查看>>
区块链最全书单|深聊了50个微信群,学习区块链必读这20本书
查看>>
20个热门在线少儿编程网站【2019】
查看>>
Netty 即时通信 后端 (五)
查看>>