redux-saga入门

摘要:
Redux page和Redux trunk是Redux的类似中间件,用于处理异步操作。Redux saga使用ES6的生成器函数来避免Redux trunk的回调写入方法,并且易于测试。Redux saga提供了一些辅助功能,用于在向商店发起操作时派生人员。takeEvery()可以在动作启动时启动任务。从“redux saga”函数*watchFetchData(){yield*takeEvery}takeLatest()和takeEvent()中导入{takeEvery}具有类似的功能。不同之处在于,takeEvent()允许同时启动多个任务,也就是说,即使启动的任务尚未结束,也将启动一个新任务。

redux-sage和redux-thunk类似都是redux的中间件,都用于处理异步操作。redux-saga使用ES6的Generator功能,避免了redux-thunk的回调写法,并且便于测试。

下面展示了最简单是使用示例

import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'
import Api from '...'

// worker Saga : 将在 USER_FETCH_REQUESTED action 被 dispatch 时调用
function* fetchUser(action) {
   try {
      const user = yield call(Api.fetchUser, action.payload.userId);
      yield put({type: "USER_FETCH_SUCCEEDED", user: user});
   } catch (e) {
      yield put({type: "USER_FETCH_FAILED", message: e.message});
   }
}

/*
  在每个 `USER_FETCH_REQUESTED` action 被 dispatch 时调用 fetchUser
  允许并发(译注:即同时处理多个相同的 action)
*/
function* mySaga() {
  yield takeEvery("USER_FETCH_REQUESTED", fetchUser);
}

/*
  也可以使用 takeLatest

  不允许并发,dispatch 一个 `USER_FETCH_REQUESTED` action 时,
  如果在这之前已经有一个 `USER_FETCH_REQUESTED` action 在处理中,
  那么处理中的 action 会被取消,只会执行当前的
*/
function* mySaga() {
  yield takeLatest("USER_FETCH_REQUESTED", fetchUser);
}

export default mySaga;
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'

import reducer from './reducers'
import mySaga from './sagas'

// create the saga middleware
const sagaMiddleware = createSagaMiddleware()
// mount it on the Store
const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
)

// then run the saga
sagaMiddleware.run(mySaga)

// render the application

put等一些方法是saga提供的指令,返回一个Effect,Effect是一个简单的js对象,包含了要被sgag middleware执行的指令,当middleware拿到一个被saga yield的Effect,它会暂停saga,直到Effect执行完成,然后saga回恢复执行。

redux-saga提供一些辅助函数,用于在action被发起到store是派生人物。

takeEvery()可以在某个action发起是启动一个任务

import { takeEvery } from 'redux-saga'

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

takeLatest()和takeEvent()功能类似,不同的是takeEvent()允许同时启动多个任务,即使已启动的任务未结束,也会启动一个新的任务。takeLatest()同时只允许启动一个任务,一个新的任务启动,之前的任务即使未完成也会被取消。

如果有多个sage监听不同的action

import { takeEvery } from 'redux-saga/effects'

// FETCH_USERS
function* fetchUsers(action) { ... }

// CREATE_USER
function* createUser(action) { ... }

// 同时使用它们
export default function* rootSaga() {
  yield takeEvery('FETCH_USERS', fetchUsers)
  yield takeEvery('CREATE_USER', createUser)
}

在 Generator 函数中,yield 右边的任何表达式都会被求值,结果会被 yield 给调用者。

测试时我我们不可能真正的执行任务发到服务器,我们需要检测的只是yield后面语句调用(通常是调用参数的检查)或值是否正确。但当yield 一个返回值是Promise的方法时,就没办法比较了,所以当yield一个异步api时使用saga提供的call()方法代替异步api的直接调用,call()返回一个普通的js对象,所以在测试时可以很容易检测。

import { call } from 'redux-saga/effects'

function* fetchProducts() {
  const products = yield call(Api.fetch, '/products')
  // ...
}
import { call } from 'redux-saga/effects'
import Api from '...'

const iterator = fetchProducts()

// expects a call instruction
assert.deepEqual(
  iterator.next().value,
  call(Api.fetch, '/products'),
  "fetchProducts should yield an Effect call(Api.fetch, './products')"
)

当dispatch一个action时,也同样难以测试,所以saga提供了put()方法来代替直接调用dispatch。

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 { call, put } from 'redux-saga/effects'
import Api from '...'

const iterator = fetchProducts()

// 期望一个 call 指令
assert.deepEqual(
  iterator.next().value,
  call(Api.fetch, '/products'),
  "fetchProducts should yield an Effect call(Api.fetch, './products')"
)

// 创建一个假的响应对象
const products = {}

// 期望一个 dispatch 指令
assert.deepEqual(
  iterator.next(products).value,
  put({ type: 'PRODUCTS_RECEIVED', products }),
  "fetchProducts should yield an Effect put({ type: 'PRODUCTS_RECEIVED', products })"
)

错误处理

使用try...catch来处理错误

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 })
  }
}

在测试时使用throw来抛出一个错误

import { call, put } from 'redux-saga/effects'
import Api from '...'

const iterator = fetchProducts()

// 期望一个 call 指令
assert.deepEqual(
  iterator.next().value,
  call(Api.fetch, '/products'),
  "fetchProducts should yield an Effect call(Api.fetch, './products')"
)

// 创建一个模拟的 error 对象
const error = {}

// 期望一个 dispatch 指令
assert.deepEqual(
  iterator.throw(error).value,
  put({ type: 'PRODUCTS_REQUEST_FAILED', error }),
  "fetchProducts should yield an Effect put({ type: 'PRODUCTS_REQUEST_FAILED', error })"
)

免责声明:文章转载自《redux-saga入门》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Kafka速览如何使用Countifs函数动态统计下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Unity多语言本地化改进版

简介 之前捣鼓过一个通过csv配置游戏多语言支持的小工具,但是发现使用过程中,通过notepad++去进行转码很不方便,并且直接将配置的csv不加密的放在游戏中心里感觉不是很踏实 于是乎~~ 新的方案 1.在PC/MAC平台上解析多语言配置,也就是editor运行环境中解析csv或者excel 2.通过在Editor运行过程中生成多个语言对象,然后序列化并...

QMesageBox的使用

一、使用构造函数弹出对话框 1、 QMessageBox msgBox;//最简单的对话框,里面什么也没有   QString str = “test”;   msgBox.setText(str);   msgBox.exec(); 2、   QMessageBox message(QMessageBox::NoIcon, "Title", "Conte...

C++ Handle(句柄) part1

本文是我学习C++沉思录第6章的笔记 本文主要讲述了Handle类的概念,定义方法以及写时复制技术。 在前文(Surrogate代理类)的讲解中我们了解到了代理的实现方法. 代理类有很多好处,但是麻烦的是每次都得进行复制.如果该类是经常使用并且member很多的话,这样复制的消耗是十分客观的. 因此这里就要介绍另外一种代理类,Handle,也就是句柄类....

在EggJS中使用Sequelize做联表查询

内容转自https://www.jianshu.com/p/078087c69b77,感谢 1.EggJS引用Sequelize 安装sequelize依赖和mysql驱动 cnpm i egg-sequelize mysql2 -S 启用sequelize插件   在config/plugin.js里面添加 sequelize: { enable...

c++ __declspec关键字详细用法

c++ __declspec关键字详细用法       __declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。其它的有关存储方式的修饰符如static与extern等是C和C++语言的ANSI规范,而__declspec是一种扩展属性的定义。扩展属性语法简化并标准化了C和C++语言关于Microsoft的扩展。 用法:__de...

vue后台管理系统项目

项目介绍1.项目根目录文件 2.源码子目录结构 3.api目录 4.assets目录 5.components目录 6.mixins目录 7.permission目录 8.router目录 9.store目录 10.styles目录 11.utils目录 项目文件介绍1.安装element-ui组件实现按需加载 // 1.1.npm...