记一次redux-saga的项目实践总结

前言

本文主要记录了在项目中使用redux-saga的一些总结,如有错误的地方欢迎指正互相学习。

redux中的action仅支持原始对象(plain object),处理有副作用的action,需要使用中间件。中间件可以在发出action,到reducer函数接受action之间,执行具有副作用的操作。

redux-thunk 和 redux-saga 是 redux 应用中最常用的两种异步流处理方式。

之前一直使用redux-thunk处理异步等副作用操作,在action中处理异步等副作用操作,此时的action是一个函数,以dispatch,getState作为形参,函数体内的部分可以执行异步。通过redux-thunk来处理异步,action可谓是多种多样,不利于


redux-thunk


redux-thunk简单介绍

redux-thunk 的任务执行方式是从 UI 组件直接触发任务。

redux-thunk中间件可以让action创建函数先不返回一个action对象,而是返回一个函数,函数传递两个参数(dispatch,getState),在函数体内进行业务逻辑的封装

redux-thunk 的主要思想是扩展 action,使得 action 从一个对象变成一个函数。


redux-thunk使用

比如下面是一个获取礼品列表的异步操作所对应的action

 
  1. export default () => dispatch => {

  2. fetch('/api/goodList', {

  3. // fecth返回的是一个promise

  4. method: 'get', dataType: 'json' }).then(

  5. json => {

  6. var json = JSON.parse(json)

  7. if (json.code === 200) {

  8. dispatch({ type: 'init', data: json.data })

  9. }

  10. }, error => { console.log(error) }

  11. )

  12. }

从这个具有副作用的action中,我们可以看出,函数内部极为复杂。如果需要为每一个异步操作都如此定义一个action,显然action不易维护。


redux-thunk缺点

总结一下redux-thunk缺点有如下几点:

  1. action 虽然扩展了,但因此变得复杂,后期可维护性降低;

  2. thunks 内部测试逻辑比较困难,需要mock所有的触发函数;

  3. 协调并发任务比较困难,当自己的 action 调用了别人的 action,别人的 action 发生改动,则需要自己主动修改;

  4. 业务逻辑会散布在不同的地方:启动的模块,组件以及thunks内部。



redux-saga


redux-saga简单介绍

redux-saga文档中是这样介绍的:

redux-saga 是一个用于管理应用程序 Side Effect(副作用,例如异步获取数据,访问浏览器缓存等)的 library,它的目标是让副作用管理更容易,执行更高效,测试更简单,在处理故障时更容易。

刚开始了解Saga时,看官方解释,并不是很清楚到底是什么?Saga的副作用(side effects)到底是什么?

通读了官方文档后,大概了解到,副作用就是在action触发reduser之后执行的一些动作, 这些动作包括但不限于,连接网络,io读写,触发其他action。并且,因为Sage的副作用是通过redux的action触发的,每一个action,sage都会像reduser一样接收到。并且通过触发不同的action, 我们可以控制这些副作用的状态, 例如,启动,停止,取消。

所以,我们可以理解为Sage是一个可以用来处理复杂的异步逻辑的模块,并且由redux的action触发。

saga特点:

  1. 1.saga的应用场景是复杂异步,如长时事务LLT(long live.transcation)等业务场景。

  2. 2.方便测试,可以使用takeEvery打印logger。

  3. 3.提供takeLatest/takeEvery/throttle方法,可以便利的实现对事件的仅关注最近事件、关注每一次、事件限频

  4. 4.提供cancel/delay方法,可以便利的取消、延迟异步请求

  5. 5.提供race(effects),[…effects]方法来支持竞态和并行场景

  6. 6.提供channel机制支持外部事件

Redux Saga适用于对事件操作有细粒度需求的场景,同时他们也提供了更好的可测试性。


redux-saga使用

注意:⚠️redux-saga是通过ES6中的generator实现的(babel的基础版本不包含generator语法,因此需要在使用saga的地方import ‘babel-polyfill’)。

redux-saga本质是一个可以自执行的generator。

在 redux-saga 中,UI 组件自身从来不会触发任务,它们总是会 dispatch 一个 action 来通知在 UI 中哪些地方发生了改变,而不需要对 action 进行修改。redux-saga 将异步任务进行了集中处理,且方便测试。

所有的东西都必须被封装在 sagas 中。sagas 包含3个部分,用于联合执行任务:

worker saga

(1)做所有的工作,如调用 API,进行异步请求,并且获得返回结果

watcher saga

(2)监听被 dispatch 的 actions,当接收到 action 或者知道其被触发时,调用 worker saga 执行任务

(3)root saga

立即启动 sagas 的唯一入口

项目中我是这样用的,如果你有更好的实现方法请分享给我:

给redux添加中间件

在定义生成store的地方,引入并加入redux-sage中间件。

 
  1. // store/index.js

  2. import { createStore, applyMiddleware, compose } from 'redux'

  3. import { routerMiddleware } from 'react-router-redux'

  4. import createSagaMiddleware from 'redux-saga'

  5. import createHistory from 'history/createHashHistory'

  6. import { createLogger } from 'redux-logger'

  7. import { rootSaga } from '../rootSaga'

  8. import reducers from '../reducers/saga-reducer'

  9. const history = createHistory()

  10. const middlewareRouter = routerMiddleware(history)

  11. const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

  12. const loggerMiddleware = createLogger({ collapsed: true })

  13. // 这是一个可以帮你运行saga的中间件

  14. const sagaMiddleware = createSagaMiddleware()

  15. const store = createStore(reducers,

  16. composeEnhancers(

  17. applyMiddleware(

  18. sagaMiddleware, middlewareRouter, loggerMiddleware

  19. )))

  20. // 通过中间件执行或者说运行saga

  21. sagaMiddleware.run(rootSaga, store)

  22. window.store = store

  23. export default store

说明:程序启动时,run(rootSaga) 会开启 sagaMiddleware 对某些 action 进行监听,当后续程序中有触发 dispatch(action) (比如:用户点击)的时候,由于数据流会经过 sagaMiddleware,所以 sagaMiddleware 能够判断当前 action 是否有被监听?如果有,就会进行相应的操作(比如:发送一个异步请求);如果没有,则什么都不做。

 
  1. // rootSaga.js

  2. // 处理浏览器兼容问题

  3. import 'babel-polyfill'

  4. import { all,call } from 'redux-saga/effects'

  5. import { lotterySagaRoot } from './components'

  6. import { getchampionListFlow, getTabsListFlow } from './container'

  7. export function* rootSaga () {

  8. yield all([call(getTabsListFlow),

  9. call(getchampionListFlow),

  10. call(lotterySagaRoot),

  11. ])

  12. }

rootSaga是我们实际发送给Redux中间件的。

rootSaga在应用程序启动时被触发一次,可以被认为是在后台运行的进程,监视着所有的动作派发到仓库(store)。

我们单拿出一个 getTabsListFlow 这个saga来进行讲解究竟发生了什么?

写到这里有必要说一下业务逻辑了,getTabsListFlow这个函数是一个watcher saga,它 watch 的谁呢?getTabsList这个worker saga函数,废话不多说看代码:

 
  1. // 处理浏览器兼容问题

  2. import 'babel-polyfill'

  3. import { call, put, take, fork } from 'redux-saga/effects'

  4. import * as types from '../../action_type'

  5. import { lists } from '../../actions/server'

  6. const { GETLIST, TABS_UPDATE, START_FETCH, FETCH_ERROR, FETCH_END } = types

  7. //----worker

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值