redux-saga_pub culture

大家好,又见面了,我是你们的朋友全栈君。

本文用以记录从调研Redux Saga,到应用到项目中的一些收获。

项目链接: https://github.com/fanxiao168/React-todoList 什么是Redux Saga

官网解释 来自:https://github.com/redux-saga/redux-saga

redux-saga is a library that aims to make side effects (i.e. asynchronous things like data fetching and impure things like accessing the browser cache) in React/Redux applications easier and better.

The mental model is that a saga is like a separate thread in your application that’s solely responsible for side effects. redux-saga is a redux middleware, which means this thread can be started, paused and cancelled from the main application with normal redux actions, it has access to the full redux application state and it can dispatch redux actions as well.

刚开始了解Saga时,看官方解释,并不是很清楚到底是什么?Saga的副作用(side effects)到底是什么?

通读了官方文档后,大概了解到,副作用就是在action触发reduser之后执行的一些动作, 这些动作包括但不限于,连接网络,io读写,触发其他action。并且,因为Sage的副作用是通过redux的action触发的,每一个action,sage都会像reduser一样接收到。并且通过触发不同的action, 我们可以控制这些副作用的状态, 例如,启动,停止,取消。

所以,我们可以理解为Sage是一个可以用来处理复杂的异步逻辑的模块,并且由redux的action触发。

使用Saga解决的问题

最初,在开始探究Saga之前,我们是希望寻求一种方式来隔离开应用前端的展现层,业务层和数据层。 大概想法是使用react展现数据,redux管理数据,然后借助redux的middleware来实现业务层。这样原有的react为核心的项目架构,变成了redux为核心的架构。

在最初的调研中redux-thunk是首先考虑的,redux-thunk是在action作用到reducer之前触发一些业务操作。刚好起到控制层的作用。

但是,马上了解到了redux-sage,因为大家都在对比两者。本文并不会做对比,在文章的最后会简单介绍为什么选了Saga而不是thunk的原因,仅供参考。

在浏览了很多比较文章后,最终,我们选择了redux-saga来处理应用的控制层。

下面是一个简单的例子:

在用户提交表单的时候,我们想要做如下事情:

校验一些输入信息 (简单, 写在组件里) 弹起提示信息(聪明的我,一定要写一个公用的提示信息模块,这样别的页面引入就可以用了, 呵呵呵呵。。。) 提交后端服务 (直接组件里面fetch吧。。。) 拿到后端返回状态 (promise so easy…) 隐藏提示信息 (这个有点难度,不过难不倒我,我给组建加一个控制属性) 更新redux store (dispatch咯。。。) 好了,现在我们要把刚刚做的事情加到所有的表单上。。。 (WTF, 每个form组件都要做同样的事情。。。页面的代码丑的不想再多看一眼。。。)

用了redux-saga之后:

form组件触发提交action (一行简单的dispatch) reducer这个action不需要我处理 (打酱油了) saga提交表单的副作用走起~ (监听到触发副作用的action) 校验一下 通知显示层弹起信息框 (dispatch一下变更控制信息框弹起的store) 提交表单 (yield一个promis,yield是javascript generator的语法,稍后有介绍) 拿到后端返回状态 更新redux store (dispatch一下) 3265839-1e5cf739fe7c1784.jpg redux-saga-01.jpg 可以看到在使用了Saga后,react只负责数据如何展示,redux来负责数据的状态和绑定数据到react,而Saga处理了大部分复杂的业务逻辑。

通过这个改变,前端应用的代码结构更加清晰,业务层可复用的部分增加。当然,Saga对自动化测试也支持的很好,可以将逻辑单独使用自动化脚本测试,提高项目质量。

开始前需要了解的几个概念

redux中间件

redux中文文档解释如下:

如果你使用过 Express 或者 Koa 等服务端框架, 那么应该对 middleware 的概念不会陌生。 在这类框架中,middleware 是指可以被嵌入在框架接收请求到产生响应过程之中的代码。例如,Express 或者 Koa 的 middleware 可以完成添加 CORS headers、记录日志、内容压缩等工作。middleware 最优秀的特性就是可以被链式组合。你可以在一个项目中使用多个独立的第三方 middleware。

相对于 Express 或者 Koa 的 middleware,Redux middleware 被用于解决不同的问题,但其中的概念是类似的。它提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。 你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。

可以简单理解为,中间件是可以在action到达reducer之前做一些事情的层。(有意思的是,saga应该是在reducer被触发之后才触发的。TODO, 需要进一步验证)

Javascript Generator

在使用Saga之前,建议先了解Javascript生成器,因为Saga的副作用都是通过生成器来实现的。

可以在阮一峰的ECMAScript 6 入门: Generator 函数的语法和Generator 函数的异步应用章节中了解更多细节。

如何使用

redux-sage官方文档有很详细的使用说明,这里只做简单的上手说明。

安装redux-sage

npm install –save redux-saga 给redux添加中间件

在定义生成store的地方,引入并加入redux-sage中间件。

import { createStore ,applyMiddleware ,compose} from 'redux';
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga'
import todoSagas from './sagas';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const sagaMiddleware = createSagaMiddleware()
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));
const store = createStore(reducer, enhancer);

sagaMiddleware.run(todoSagas);

export default store;

副作用

副作用,顾名思义,在主要作用(action触发reducer)之外,用来处理其他业务逻辑。redux-saga提供了几种产生副作用的方式, 主要用到了有两种takeEvery和takeLates。

takeEvery会在接到相应的action之后不断产生新的副作用。 比如,做一个计数器按钮,用户需要不断的点击按钮,对后台数据更新,这里可以使用takeEvery来触发。

takeLatest在相同的action被触发多次的时候,之前的副作用如果没有执行完,会被取消掉,只有最后一次action触发的副作用可以执行完。比如,我们需要一个刷新按钮, 让用户可以手动的从后台刷新数据, 当用户不停单机刷新的时候, 应该最新一次的请求数据被刷新在页面上,这里可以使用takeLatest。

sagas.js

import { takeEvery ,put }  from 'redux-saga/effects';
import { GET_INIT_LIST } from './actionTypes';
import { getInitListAction } from './actionCreators';
import axios from 'axios';

function* getInitList() {
	try {
		const res = yield axios.get('/list.json');
		const action = getInitListAction(res.data);
		yield put(action);
	}catch(e){
		console.log('list.json网络请求失败');
	}
}

//generator 函数
function* mySaga() {
  yield takeEvery(GET_INIT_LIST,getInitList);
}

export default mySaga;

TodoList.js

	componentDidMount() {
		const action = getInitList();
		store.dispatch(action);
	}

注意,takeEvery第一个参数可以是数组或者方法。 也可以有第三个参数用来传递变量给方法。

call方法

call有些类似Javascript中的call函数, 不同的是它可以接受一个返回promise的函数,使用生成器的方式来把异步变同步。

put方法

put就是redux的dispatch,用来触发reducer更新store

有什么弊端

目前在项目实践中遇到的一些问题:

redux-saga模型的理解和学习需要投入很多精力 因为需要用action触发,所以会产生很多对于reducer无用的action, 但是reducer一样会跑一轮,虽然目前没有观测到性能下降,但还是有计算开销 在action的定义上要谨慎,避免action在saga和reducer之间重复触发,造成死循环 后记

总体而言,对于redux-saga的第一次尝试还是很满意的。 在业务逻辑层,可以简化代码,使代码更加容易阅读。 在重用方面,解耦显示层和业务层之后, 代码的重用度也得到了提升。

选择Saga的原因

开始的时候一直在犹豫是否需要使用Saga或thunk,因为并不能很好的把握这两者到底解决了什么问题。之后,在浏览文章的时候看到了一遍对比两者的长文,列出了不少开发者对两者的担忧和争论,其中不乏闪光的观点,长文的最后作者写到:“不管是否用得上,你都应该尝试一下”。 这句话使我决定了尝试用saga或thunk来实践把前端分层的设想。

之所以最后选择了saga是因为这段 Cheng Lou 的视频: On the Spectrum of Abstraction (youtube)

视频中讲述了在一种抽象的概念下如何去选择一种技术。 其中一个理论是:越是用来解决具体问题的技术,使用起来越容易,越高效,学习成本越低;越是用来解决宽泛问题的技术,使用起来越难,学习成本越高。 thunk解决的是很具体的一个问题,就是在action到达reducer之前做一些其他的业务,比如fetch后端, 它在做这件事的上很高效。而Saga解决的问题要更宽泛一些,因为saga只是拦截了action,至于做什么,开发者需要自己来考虑,可以是fetch后端,也可以是更新redux store, 甚至可以执行action带进来的callback。 很显然对于一个业务层来说,saga会是一个更合适的选择,但同时也带来了学习成本的提高。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/191679.html原文链接:https://javaforall.cn

原文地址:https://cloud.tencent.com/developer/article/2152137

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340