React-Redux-Saga

简介: React-Redux-Saga

Redux-saga 简介


  • redux-saga 和 redux-thunk 一样, 是一个 Redux 中获取存储异步数据的中间件
  • redux-saga 可以直接拦截 dispatch 派发的 action, 从而实现在执行 reducer 之前执行一些其它操作




使用 Redux-saga


  • 安装 Redux-saga
npm install redux-saga


  • 在创建 store 时应用 redux-saga 中间件,更改 store.js
import {createStore, applyMiddleware} from 'redux'
/*
注意点: 如果导入的是redux-thunk, 那么返回给我们的是一个中间件对象
       如果导入的是redux-saga, 那么返回给我们的是一个用于创建中间件对象的方法
* */
import createSagaMiddleware from 'redux-saga'
import reducer from './reducer';
// 通过createSagaMiddleware方法创建saga中间件对象
const sagaMiddleware = createSagaMiddleware();
// 创建store之前,通过applyMiddleware方法,告诉Redux需要应用哪些中间件
const storeEnhancer = applyMiddleware(sagaMiddleware);
// 利用store来保存状态(state)
const store = createStore(reducer, storeEnhancer);
/*
注意点: 如果是redux-thunk, 那么在创建store的时候指定完中间件即可
       如果是redux-saga, 那么除了需要在创建store的时候指定中间件以外, 还需要手动的调用中间件的run方法才行
* */
sagaMiddleware.run(undefined, undefined);
export default store;


  • 我们可以利用传入的生成器告诉 redux-saga, 需要拦截哪些 dispatch 派发的 action,声明一下,至于什么是生成器可去查看一下博主 JS 流程框架与特性 的标签里面会进行介绍什么是生成器,然后这个陌生的问题就过,我们继续,创建 saga.js 在当中定义生成器代码,在生成器函数中获取网络数据:
import {takeEvery, put} from 'redux-saga/effects'
import {GET_USER_INFO} from './constants';
import {changeAction} from './action';
function* myHandler() {
    // 获取网络数据
    const data = yield fetch('http://127.0.0.1:7001/info')
        .then((response) => {
            return response.json();
        })
        .catch((error) => {
            console.log(error);
        });
    // 保存获取到的数据
    // 相当于 store.dispatch(changeAction());
    yield put(changeAction(data));
}
function* mySaga() {
    // 指定需要拦截的action类型
    // 指定拦截到这个类型的action之后交给谁来处理
    yield takeEvery(GET_USER_INFO, myHandler)
}
export default mySaga;


如上自定义函数已经获取到了网络数据,添加到 Redux 中保存是通过 Saga 提供的 put 方法进行添加即可,在更改 store.js 告诉 saga 中间件的生成器哪些通过 dispatch 派发的 action 需要进行拦截, 在 run 方法进行指定:

  • 在组件中派发 action 这回我们派发的 action 就不用像 thunk 一样派发一个函数了

除了通过 takeEvery 来拦截派发的 action 任务方式之外还可以通过 takeLatest 进行监听。




takeEvery 和 takeLatest 区别


区别主要在于是否能够完整的执行监听方法:

  • 对于 takeEvery 而言,每次拦截到对应类型的 action, 都会完整的执行监听方法
  • 对于 takeLatest 而言, 每次拦截到对应类型的 action, 都不能保证一定能够完整的执行监听方法

例如: 连续派发了 3 次 GET_USER_INFO 的 action, 那么对于 takeEvery 而言, myHandler 就会被完整的执行 3 次,那么对于 takeLatest 而言, 如果派发下一次同类型 action 的时候,上一次派发的 action 还没有处理完, 也就是上一次的监听方法还没有处理完,那么 takeLatest 会放弃还没有处理完的代码, 直接开始处理下一次的 action。


那么问题来了,如果想要验证如上博主所说的这点,就必须要派发多次 action 那么该如何进行派发呢,正好可以借助该问题就可以引出一个全新的知识点了那么就是连续派发多个 action,如果我们只需要拦截一个类型的 action, 那么直接通过 yield takeEvery / yield takeLatest 即可,但是如果我们想同时拦截多个类型的 action, 那么我们就必须借助另外一个函数, all()

sage.js:

import {takeLatest, put, all} from 'redux-saga/effects'
import {GET_USER_INFO, ADD_COUNT, SUB_COUNT} from './constants';
import {changeAction} from './action';
function* myHandler() {
    // 获取网络数据
    const data = yield fetch('http://127.0.0.1:7001/info')
        .then((response) => {
            return response.json();
        })
        .catch((error) => {
            console.log(error);
        });
    yield put(changeAction(data));
    console.log('myHandler');
}
function* mySaga() {
    yield all([
        yield takeLatest(GET_USER_INFO, myHandler),
        yield takeLatest(GET_USER_INFO, myHandler),
        yield takeLatest(GET_USER_INFO, myHandler),
    ]);
}
export default mySaga;

About.js:

import React from 'react';
import {changeAction, getUserInfo, addAction} from "../store/action";
import connect from "../connect/connect";
import {ADD_COUNT} from "../store/constants";
class About extends React.PureComponent {
    componentDidMount() {
        this.props.getUserInfo();
    }
    render() {
        return (
            <div>
                <p>{this.props.info.name}</p>
                <p>{this.props.info.age}</p>
            </div>
        )
    }
}
const mapStateToProps = (state) => {
    return {
        info: state.info,
        count: state.count
    }
};
const mapDispatchToProps = (dispatch) => {
    return {
        changeInfo() {
            dispatch(changeAction());
        },
        getUserInfo(){
            dispatch(getUserInfo())
        },
        addCount(){
            dispatch(addAction(1))
        }
    }
};
export default connect(mapStateToProps, mapDispatchToProps)(About);

关于如上博主举的 takeLatest 栗子没有体现出来,不知道是否是本地体现不了该场景,如有大佬发现问题,还请在下方评论区指出,共同学习。(博主所说的是:如果派发下一次同类型 action 的时候,上一次派发的 action 还没有处理完, 也就是上一次的监听方法还没有处理完)


如果我们只需要保存一个数据, 那么直接通过 yield put 即可,但是如果我们想同时保存多个数据 , 那么我们就必须借助另外一个函数, all()


saga.js:

import {takeLatest, put, all} from 'redux-saga/effects'
import {GET_USER_INFO, ADD_COUNT, SUB_COUNT} from './constants';
import {changeAction} from './action';
function* myHandler() {
    // 获取网络数据
    const data1 = yield fetch('http://127.0.0.1:7001/info')
        .then((response) => {
            return response.json();
        })
        .catch((error) => {
            console.log(error);
        });
    const data2 = yield fetch('http://127.0.0.1:7001/info')
        .then((response) => {
            return response.json();
        })
        .catch((error) => {
            console.log(error);
        });
    yield all([
        yield put(changeAction(data1)),
        yield put(changeAction(data2)),
        yield put({type: 'CHANGE_INFO', info: {name: 'test'}}),
        yield put({type: 'CHANGE_USER_Age', age: data1.age}),
    ])
}
function* mySaga() {
    yield all([
        yield takeLatest(GET_USER_INFO, myHandler),
        yield takeLatest(ADD_COUNT, myHandler),
        yield takeLatest(SUB_COUNT, myHandler),
    ]);
}
export default mySaga;


About.js:

import React from 'react';
import {changeAction, getUserInfo} from "../store/action";
import connect from "../connect/connect";
class About extends React.PureComponent {
    componentDidMount() {
        this.props.changeInfo();
        this.props.getUserInfo();
    }
    render() {
        return (
            <div>
                <p>{this.props.info.name}</p>
                <p>{this.props.info.age}</p>
            </div>
        )
    }
}
const mapStateToProps = (state) => {
    return {
        info: state.info
    }
};
const mapDispatchToProps = (dispatch) => {
    return {
        changeInfo() {
            dispatch(changeAction());
        },
        getUserInfo(){
            dispatch(getUserInfo())
        }
    }
};
export default connect(mapStateToProps, mapDispatchToProps)(About);

官方文档地址:https://redux-saga-in-chinese.js.org/




最后

本期结束咱们下次再见👋~

🌊 关注我不迷路,如果本篇文章对你有所帮助,或者你有什么疑问,欢迎在评论区留言,我一般看到都会回复的。大家点赞支持一下哟~ 💗

相关文章
|
关系型数据库 MySQL 数据库
n8n自动化工具部署与使用
n8n是一款开源的工作流自动化工具,类似于IFTTT。它的优点是开源、可以自托管、下载安装方便、易于使用,可以互联上百种服务。n8n基于节点能够将任何工具连接在一起,轻松部署不同类型的任务。它可以做很多事情,比如:从数据库中获取数据后下载为excel然后通过邮件发送给其他人。
9428 1
|
弹性计算 Cloud Native Devops
云效DevStudio体验
阿里云中提供了在线编辑工具DevStudio,让开发更加便捷。
2313 0
云效DevStudio体验
|
9月前
|
传感器 监控 前端开发
产品经理-面试自我介绍
面试自我介绍主要包括个人基本信息、教育经历和工作经历。工作经历按时间倒序描述,重点介绍最近的工作内容与项目经验。例如:我叫小宋,毕业于浙江大学,12年B端产品经验,涉及智慧城市、智慧医疗等项目。项目经历中需说明角色、解决问题的能力及团队结构,如智慧城市项目的智能交通管理和能源管理等模块的规划与实施。成功的产品应符合公司商业价值并满足用户核心诉求。
|
10月前
|
SQL Java 数据库连接
MyBatis-Plus快速入门:从安装到第一个Demo
本文将带你从零开始,快速入门 MyBatis-Plus。我们将首先介绍如何安装和配置 MyBatis-Plus,然后通过一个简单的示例演示如何使用它进行数据操作。无论你是 MyBatis 的新手还是希望提升开发效率的老手,本文都将为你提供清晰的指导和实用的技巧。
2701 0
MyBatis-Plus快速入门:从安装到第一个Demo
|
机器学习/深度学习 传感器 算法
基于混沌系统logistic实现图像加密,解密附matlab代码
基于混沌系统logistic实现图像加密,解密附matlab代码
|
传感器 数据采集 监控
资料转发分享【毕业设计】单片机和stm32设计选题,proteues仿真、程序完整资料
资料转发分享【毕业设计】单片机和stm32设计选题,proteues仿真、程序完整资料 基于单片机寻迹巡线避障智能小车系统设计 基于单片机体温心率脉搏检测仪系统设计 基于单片机温湿度光照自动窗帘系统设计 基于单片机环境监测温湿度PM2.5系统设计 基于51单片机的波形发生器(四种波形) 基于单片机SO2 NO2 PM温湿度空气质量检测仪 基于51单片机冰箱温度控制器设计
661 1
资料转发分享【毕业设计】单片机和stm32设计选题,proteues仿真、程序完整资料
|
网络协议 安全 测试技术
常见内网穿透工具,收好了!(二)
常见内网穿透工具,收好了!
常见内网穿透工具,收好了!(二)
|
IDE 前端开发 小程序
阿里 & 蚂蚁自研 IDE 研发框架 OpenSumi 正式开源
经历近 3 年时间,在阿里集团及蚂蚁集团共建小组的努力下,OpenSumi 作为国内首个强定制性、高性能,兼容 VS Code 插件体系的 IDE 研发框架,今天正式对外开源。
1136 5
阿里 & 蚂蚁自研 IDE 研发框架 OpenSumi 正式开源
|
存储 SQL 关系型数据库
【MySQL】数据库进阶之触发器内容详解
文章目录 1 触发器概述 2 触发器的基本操作 2.1 创建触发器 2.2 触发器操作实例 3 NEW与OLD 3.1 为什么需要NEW与OLD? 3.2 NEW与OLD实例 4 触发器的其他操作 5 触发器的注意事项
【MySQL】数据库进阶之触发器内容详解
|
前端开发 JavaScript 程序员
Dreamweaver过时了吗值得学吗
Dreamweaver过时了吗值得学吗
770 0