redux-Saga

概念

image

redux-saga是redux的中间件,中间件的作用是为redux提供额外的功能,用来处理异步产生的副作用

sages使用generator来yield Effects
effects API 如 fork,call,take,put,cancel 等来创建 Effect。

redux-saga

//拿到createSagaMiddleware中间件
import createSagaMiddleware from "redux-saga";

//创建中间件
const sagaMiddleware = createSagaMiddleware()

//将中间件注入store
const store = createStore(reducer, applyMiddleware(sagaMiddleware))

//启动中间间,将rootSaga配置放入中间件
sagaMiddleware.run(rootSaga)

saga配置

//redux-saga/effects拿到处理异步dispatch的方法
import { put, takeEvery, delay } from "redux-saga/effects";

//模拟异步请求,action的时候执行
export function* incrementAsync() {
    //延时
  yield delay(1000);
  //派发action
  yield put({ type: "INCREMENT" });
}
//中间件启动的时候执行
export default function* rootSaga() {
  //并行执行异步请求
  yield takeEvery("INCREMENT_ASYNC", incrementAsync);
}

//模拟执行过程
<Counter
  value={store.getState()}
  onIncrement={() => action('INCREMENT')}
  onDecrement={() => action('DECREMENT')}
  onIncrementIfOdd={() => action('INCREMENT_IF_ODD')}
  onIncrementAsync={() => action('INCREMENT_ASYNC')}
/>,


//takeLatest
export function* incrementAsync() {
  yield delay(500);
  yield put({ type: "INCREMENT" });//只派发最新的一次action
}

export default function* rootSaga() {
  //只执行最新的action
  yield takeLatest("INCREMENT_ASYNC", incrementAsync);
}

redux-saga分类

worker saga做调用api,的异步操作
watcher saga监听被dispatch的actions,收到actions消息后通知worker执行任务
root saga 立即启动saga的唯一入口

Effect概念

一个 Saga 所做的实际上是组合那些所有的 Effect,共同实现所需的控制流。 最简单的例子是直接把 yield 一个接一个地放置来对序列化 yield Effect。你也可以使用熟悉的控制流操作符(if, while, for) 来实现更复杂的控制流。

错误处理,try & catch

//用try,catch来捕获异步执行中的错误
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 })
  }
}

dispatch action,put

//用put来派发异步请求结果action
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 })
}

声明式Effects,call

//用call来代替普通的异步请求
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')"
)

Saga Helpers,takeLates * takeEvery

import { takeLatest } from 'redux-saga'

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

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

监听未来的action,take

//使用take监听特定的action
import { take, put } from 'redux-saga/effects'

function* watchFirstThreeTodosCreation() {
  for (let i = 0; i < 3; i++) {
    const action = yield take('TODO_CREATED')
  }
  yield put({type: 'SHOW_CONGRATULATION'})
}

无阻塞调用fork

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

同时执行多个任务


const [users, repos] = yield [
  call(fetch, '/users'),
  call(fetch, '/repos')
]

竞赛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'})
}
posted @ 2019-03-21 10:54  pluscat  阅读(259)  评论(0编辑  收藏  举报