react系列笔记:第三记-redux-saga

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

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

 

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

使用:redux

import createSagaMiddleware from 'redux-saga'
import {createStore,applyMiddleware} from 'redux'

const saga = createSagaMiddleware();

const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(mysagas);
  

 

基础概念:promise

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

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

辅助函数:异步

  takeEvery : 能够同时启动屡次任务函数

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

声明式的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:

  防抖动

相关文章
相关标签/搜索