zoukankan      html  css  js  c++  java
  • react系列笔记:第三记-redux-saga

    github : https://github.com/redux-saga/redux-saga

    文档:https://redux-saga.js.org/  

    redux-saga:  redux中间件,旨在处理应用中的副作用

    使用:

    import createSagaMiddleware from 'redux-saga'
    import {createStore,applyMiddleware} from 'redux'
    
    const saga = createSagaMiddleware();
    
    const store = createStore(
      reducer,
      applyMiddleware(sagaMiddleware)
    )
    sagaMiddleware.run(mysagas);
      

     

    基础概念:

      saga-middleware 检查每个被 yield 的 Effect 的类型,然后决定如何实现哪个 Effect。如果 Effect 类型是 PUT 那 middleware 会 dispatch 一个 action 到 Store。 如果 Effect 类型是 CALL 那么它会调用给定的函数。

    put({type: 'INCREMENT'}) // => { PUT: {type: 'INCREMENT'} }
    call(delay, 1000)        // => { CALL: {fn: delay, args: [1000]}}

    辅助函数:

      takeEvery : 可以同时启动多次任务

      takeLatest : 在一次任务未完成之前,遇到新任务将取消之前任务。

    声明式的effect

      call:  saga通过 Generator函数实现,在yield函数后执行effect,其中call是用于执行某些异步操作的。

    yield requestSome('/xxx');
    
    yield call(requestSome,'/xxx')
    //之所以用call取代上面的直接调用写法,好处在于,
    //编写测试代码的时候,可以deepEqual  generator函数的next().value和call(requestSome,'/xxx'),这样所有的effect都可以被测试,而不需要mock yield后的执行结果

    dispatching actions:

      put : 和上面的call一样,中间件提供put 来把action丢到中间件中去dispatch,好处同样是便于测试

    高级:

    take:

      call方法可以yield一个promise,然后会阻塞generator的执行,知道promise resolve,结果返回
      take(xxx)同理,阻塞generator直到xxx匹配的action被触发

      由此:take(*)可以用于抓取log,take(*)会匹配任意的action触发事件

      使用while(true){ take(/xxx/) }  可以创建持续的action监听,当然也可以根据需求,选择性的监听,只需改版while(xxx)的条件就行了

    function* actionLog(){
      while(true){
        yield take('INCREMENT');
        console.log('do increment');
        yield take('DECREMENT');
        console.log('do decrement')
      }
    }
    //take可以控制action的监听顺序,如上,会先监听到INCREMENT之后,才会再往下监听DECREMENT,完后继续监听INCREMENT。这在一些顺序明确的action事件里,可以将流程代码写在一起,
    //如login   logout  

    fork:

      fork和take不同,take会和call一样阻塞代码的执行,知道结果返回,fork则不会,它会将任务启动并且不阻塞代码的执行,

      fork会返回一个task,可以用cacel(task)来取消任务

      https://redux-saga.js.org/docs/advanced/NonBlockingCalls.html

      此文中将login 和logout作为例子,在login请求未返回来之前执行了logout,则需要cacel未完成的login,又不能用take(login)否则阻塞logout,会在login响应之前take不到logout。

    import { take, put, call, fork, cancel } from 'redux-saga/effects'
    
    // ...
    
    function* loginFlow() {
      while (true) {
        const {user, password} = yield take('LOGIN_REQUEST')
        // fork return a Task object
        const task = yield fork(authorize, user, password)
        const action = yield take(['LOGOUT', 'LOGIN_ERROR'])
        if (action.type === 'LOGOUT')
          yield cancel(task)
        yield call(Api.clearItem, 'token')
      }
    }
    
    
    import { take, call, put, cancelled } from 'redux-saga/effects'
    import Api from '...'
    
    function* authorize(user, password) {
      try {
        const token = yield call(Api.authorize, user, password)
        yield put({type: 'LOGIN_SUCCESS', token})
        yield call(Api.storeItem, {token})
        return token
      } catch(error) {
        yield put({type: 'LOGIN_ERROR', error})
      } finally {
        if (yield cancelled()) {
          // ... put special cancellation handling code here
        }
      }
    }

    all:

      yield表达式,可以将语句分段执行,但如果有时候想同时执行两个任务,则需要用到all

    import {all,call} from 'redux-saga/effect'
    
    //此处会同步执行两个call的任务
    const [users, repos] = yield all([
      call(fetch, '/users'),
      call(fetch, '/repos')
    ])

    race:

      和promise中的race一个概念,执行多个任务,受到响应后则继续执行  

    function* fetchPostsWithTimeout() {
      const {posts, timeout} = yield race({
        posts: call(fetchApi, '/posts'),
        timeout: call(delay, 1000)
      })
    
      if (posts)
        put({type: 'POSTS_RECEIVED', posts})
      else
        put({type: 'TIMEOUT_ERROR'})
    }

    yield * 

      通过yield * xxx()来组合多个generator任务。

    组合saga:

      可以通过yield [call(task1),call(task2)...]来组合多个generator。

    channels:

    throttle:

      节流

    delay:

      防抖动

  • 相关阅读:
    How To Build CyanogenMod Android for smartphone
    CentOS安装Code::Blocks
    How to Dual boot Multiple ROMs on Your Android SmartPhone (Upto Five Roms)?
    Audacious——Linux音乐播放器
    How to Dual Boot Multiple ROMs on Your Android Phone
    Everything You Need to Know About Rooting Your Android Phone
    How to Flash a ROM to Your Android Phone
    什么是NANDroid,如何加载NANDroid备份?
    Have you considered compiled a batman-adv.ko for android?
    BATMAN—Better Approach To Mobile Adhoc Networking (B.A.T.M.A.N.)
  • 原文地址:https://www.cnblogs.com/laojun/p/9144239.html
Copyright © 2011-2022 走看看