初识react(四) react中异步解决方案之 redux-saga

回顾

今天demo是实现一个异步的计算器,探究redux-saga工做流程html

简介

  • redux-saga 是一个 redux 的中间件,而中间件的做用是为 redux 提供额外的功能。
  • 因为在 reducers 中的全部操做都是同步的而且是纯粹的,即 reducer 都是纯函数,纯函数是指一个函数的返回结果只依赖于它的参数,而且在执行过程当中不会对外部产生反作用,即给它传什么,就吐出什么。
  • 可是在实际的应用开发中,咱们但愿作一些异步的(如Ajax请求)且不纯粹的操做(如改变外部的状态),这些在函数式编程范式中被称为“反作用”。

redux-saga 就是用来处理上述反作用(异步任务)的一个中间件。它是一个接收事件,并可能触发新事件的过程管理者,为你的应用管理复杂的流程。react

redux-saga工做原理

  • 对generator不了解的,看下阮一峰 generator讲解
  • sages 采用 Generator 函数来 yield Effects(包含指令的文本对象)。
  • Generator 函数的做用是能够暂停执行,再次执行的时候从上次暂停的地方继续执行
  • Effect 是一个简单的对象,该对象包含了一些给 middleware 解释执行的信息。
  • 你能够经过使用 effects API 如 fork,call,take,put,cancel 等来建立 Effect。

redux-saga分类

  • worker saga 作左右的工做,如调用API,进行异步请求,获取异步封装结果
  • watcher saga 监听被dispatch的actions,当接受到action或者知道其被触发时,调用worker执行任务
  • root saga 当即启动saga的惟一入口

基本介绍已经讲完了,当作完一个demo后,回头再看redux-saga官网或者上面讲解,可能会有更深的体会git

使用redux-saga实现一个异步计数器

因为目录结构跟上篇文章同样,在这里就只把变更的部分单独抽离出来说解github

一、修改actions/counter.js

  • 增长一个异步记数的动做类型。
import * as Types from "../action-types";
let actions ={
    add(num){
        return{type:Types.INCREMENT,count:num}
    },
    minus(num){
        return{type:Types.DECREMENT,count:num}
    },
    //增长了一个异步记数的类型,用于在counter.js中派发动做
    async(num){
        return {type:Types.ADD_ASYNC}
    }
};
export default actions;

复制代码

二、重点,在src目录下增长saga.js文件

//takeEvery=>负责监听  put=>派发动做   call=>告诉saga,执行delay,并传入1000做为参数
import {takeEvery,put,call} from "redux-saga/effects";
import * as Types from "./store/action-types";
const delay = ms=>new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve()
    },ms)
})
//saga分为三类 一、rootsaga 二、监听saga 三、worker干活的saga
function* add() {
    yield call(delay,1000);
    //就是指挥saga中间件向仓库派发动做
    yield put({type:Types.INCREMENT,count:10});
}
function* watchAdd() {
    //监听派发给仓库的动做,若是动做类型匹配的话,会执行对应的监听生成器
    yield takeEvery(Types.ADD_ASYNC,add)
}
export default function* rootSaga() {
    yield watchAdd()

}
复制代码

还记得上面说的,rudux-saga分类,root saga ->watcher saga -> worker saga。在这段代码中将会体现,代码咱们从上往下看。ajax

2.1 saga工做流程(代码从下往上看)
  • 默认导出了rootSaga,即saga的入口文件
  • watcher saga ->wactchAdd 负责监听派发的动做,若是动做类型匹配,执行对应的 worker saga
  • 上面的worker saga指代的是 add函数
2.2 redux-saga/effects 反作用

在实际的应用开发中,咱们但愿作一些异步的(如Ajax请求)且不纯粹的操做(如改变外部的状态),这些在函数式编程范式中被称为“反作用”。编程

  • takeEvery=>负责监听,监听派发给仓库的动做,若是动做类型匹配的话,会执行对应的监听生成器->add
  • put=>派发动做,能够理解为dispatch
  • call=>告诉saga,执行delay函数,并把参数传过去。注意: delay函数必须返回promise

讲到这里,流程就说完了,接下来在store中执行rootSagaredux

三、在store/index引入rootSaga

import {createStore,applyMiddleware} from 'redux';
    import createSagaMiddleware from "redux-saga"; //引入redux-saga
    import  rootSaga from "../saga" //引入咱们上面写好的rootSaga
    import reducer from "./reducers"
    let sagaMiddleware =createSagaMiddleware(); //执行获得saga中间件
    let store = createStore(reducer,applyMiddleware(sagaMiddleware)); //使用中间件
    sagaMiddleware.run(rootSaga); //开始执行rootSaga
    export  default  store;
复制代码

对于redux中间件没有讲解,这部份内容涉及东西比较多,也不太好理解,写这个react系列目的是尽量简单的让全部人理解,想看全部的redux源码解析,底部会留下全部总结的代码仓库。promise

四、在counter.js组件中派发这个异步动做

  • 代码跟上篇文章如出一辙,只是增长了按钮实现异步操做
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {connect} from "react-redux";
import actions from "../store/actions/counter"
class Counter extends Component {
    render() {
        console.log(this.props);
        return(
            <div>
                <h1>{this.props.number}</h1>
                <button onClick={()=>{this.props.add(5)}}>+</button>
                <button onClick={()=>{this.props.minus(1)}}>-</button>
                //增长异步操做
                <button onClick={()=>{this.props.async()}}>异步加10</button>
            </div>
        )
    }
}
export default connect(state=>({
    ...state
}),actions)(Counter)
复制代码

终结,看效果。能够看出,点击后等待1s才加10。那咱们就能够在call()中传入执行的异步函数(如ajax)来获取数据啦。咱们这个例对应的delay函数bash

最后在梳理下整个过程

  • 一、组件中调用了this.props.async(),返回的action对象=>{type:Types.ADD_ASYNC}会在connect方法中被派发app

  • 二、saga中takeEvery(Types.ADD_ASYNC,add),监听到动做的类型后,触发 worker saga =>add

  • 三、worker saga中先 yield call(delay,1000); 执行delay方法,延时1s

  • 四、yield put({type:Types.INCREMENT,count:10}); 最后派发的仍是INCREMENT的类型

  • 五、接着被reducer处理,更新state

  • 六、页面刷新

  • 更多优质文章参考

  • redux全部源码解析戳这里

相关文章
相关标签/搜索