zoukankan      html  css  js  c++  java
  • 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'})
    }
    
  • 相关阅读:
    mysql获取当前时间,及其相关操作
    notepad++ 样式随我变!
    MySQL索引的创建、删除和查看
    so easy 的弹出层——使用jquery
    mysql获取当前时间,及其相关操作
    侯捷大师畅谈技术人生与读书感悟
    《海量数据库解决方案》之聚簇表的代价
    博文视点大讲堂第44期——招聘真相全揭秘 圆满结束
    程序员修炼道路上的“葵花宝典”——博文视点大讲堂42期快乐结束
    众专家推荐
  • 原文地址:https://www.cnblogs.com/pluslius/p/10570137.html
Copyright © 2011-2022 走看看