zoukankan      html  css  js  c++  java
  • Redux-saga-整理

    介绍

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

    正常redux流程

    加入redux-saga之后的流程


    使用方式

    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)
    }
    
    //有一种用法:监控所有的发起的action
    yield 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,

    1. sagas都是用Generator函数实现的
    2. 在 Generator 函数中,yield 右边的任何表达式都会被求值,结果会被 yield 给调用者
    3. 用yield对Effect(简单对象),进行解释执行
    4. Effect 是一个简单的对象,这个对象包含了一些给 middleware 解释执行的信息。 你可以把 Effect 看作是发送给 middleware 的指令以执行某些操作(调用某些异步函数,发起一个 action 到 store,等等)
    //官方例子
    import { takeEvery } from 'redux-saga/effects'
    import Api from './path/to/api'
    
    //监听如果有一个调用PRODUCTS_REQUESTED 的action的话,就会匹配到第二个参数所代表的effect
    function* 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 时恢复 generator
    function* fetchProducts() {
      const products = yield call(Api.fetch, '/products')
      // ...
    }
    
    复制代码

    发送action到store

    //这种方式是Generator获取到了返回值,在调用dispatch
    function* 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上的action
    function mapDispatchToProps(dispatch) {
        return {
            getHome: bindActionCreators(getHomeAdData, dispatch)
        }
    }
    //一个 action creator
    export function getHomeAdData(){
        return {
            type: actionTypes.HOME_AD_DATA,
        }
    }
    //监听action.type,然后出发后面的action
    export 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
    }
    复制代码


    https://juejin.im/post/5b306e6151882574d3249605
  • 相关阅读:
    线性分类器之感知机算法
    字符串包含判断
    王家林 云计算分布式大数据Hadoop实战高手之路从零开始 第二讲:全球最详细的从零起步搭建Hadoop单机和伪分布式开发环境图文教程
    王家林 第六讲Hadoop图文训练课程:使用HDFS命令行工具操作Hadoop分布式集群初体验
    王家林的“云计算分布式大数据Hadoop实战高手之路从零开始”的第五讲Hadoop图文训练课程:解决典型Hadoop分布式集群环境搭建问题
    王家林的 第三讲Hadoop图文训练课程:证明Hadoop工作的正确性和可靠性只需4步图文并茂的过程
    王家林 第四讲Hadoop图文训练课程:实战构建真正的Hadoop分布式集群环境
    麻雀GUIv1.0整理好咯,发个开源上来。
    body设置背景色异常
    safari浏览器placeholder垂直居中
  • 原文地址:https://www.cnblogs.com/feng9exe/p/11727847.html
Copyright © 2011-2022 走看看