当前位置: 首页 > 编程日记 > 正文

[译] Don’t call me, I’ll call you:使用 Redux-Saga 管理 React 应用中的异步 action (上)...

  • 原文地址:Don’t call me, I’ll call you: Side effects management with Redux-Saga (Part 1)
  • 原文作者:David Dvora
  • 译文出自:掘金翻译计划
  • 本文永久链接:github.com/xitu/gold-m…
  • 译者:jonjia
  • 校对者:smileShirely ClarenceC

Don’t call me, I’ll call you:使用 Redux-Saga 管理 React 应用中的异步 action (上)

在接下来的两篇文章中,我想谈谈在 React 应用中使用 Redux-Saga 进行异步 action 管理的基础和进阶方法。我会说明为什么我们会在 AppsFlyer 项目中使用它,以及它可以解决什么问题。

本篇文章主要介绍 Redux-Saga 相关的基本概念,下篇专门讨论 Redux-Saga 可以解决哪些问题。请注意:阅读这两篇文章,你要对 React 和 Redux 有一定的了解。

Generators 先行!

为了理解 Sagas,我们首先要理解什么是 Generator。下面是 MDN 对 Generator 的描述:

Generator 是在执行时能暂停,后面又能从暂停处继续执行的函数。它的上下文会在继续执行时保存。

你可以把 Generator 理解成一种遍历器对象生成函数,(译注:Generator 执行后返回的遍历器对象)提供一个 next 方法。执行这个方法就会返回下一个状态,或者返回遍历结束的状态。这就需要 Generator 能够维护内部状态。

下面是一个基本的 Generator 示例,它生成的遍历器对象会返回几个字符串:

function* namesEmitter() {yield "William";yield "Jacob";return "Daniel";
}// 执行 Generator
var generator = namesEmitter();console.log(generator.next()); // prints {value: "William", done: false}console.log(generator.next()); // prints {value: "Jacob", done: false}console.log(generator.next()); // prints {value: "Daniel", done: true}
复制代码

next 方法的返回值结构非常简单 — 只要我们通过 yield/return 返回值,这个返回值就是 value 属性的值。如果我们没有返回值,value 属性的值就是 undefineddone 属性的值就是 true。 还有一点值的注意的是,执行 namesEmitter 后,函数会在调用 yield 的地方停下来。当我们调用 next 方法后,函数会继续执行,直到遇到下一个 yield。如果我们调用了 return 语句或者函数执行完毕,done 属性就会为真。

如果状态序列的长度不确定时,我们可以用下面的方法来写:

var results = generator.next();
while(!results.done){console.log(results.value);results = generator.next();
}
console.log(results.value);
复制代码

什么是 Sagas?

Sagas 是通过 Generator 函数来创建的。官方文档 的解释如下:

Saga 就像应用中的一个独立线程,完全负责管理异步 action。

你可以把 Saga 想象成一个以最快速度不断地调用 next 方法并尝试获取所有 yield 表达式值的线程。你可能会问这和 React 有什么关系,为什么要使用它,所以首先来看看如何在 React & Redux 应用使用 Saga:

在 React & Redux 应用中,一个常见的用法从调用一个 action 开始。被分配用来处理这个 action 的 reducer 会使用新的 state 更新 store,随后视图就会被更新渲染。 如果一个 Saga 被分配用来处理这个 action — 这个 action 通常就是个异步 action(比如一个对服务端的请求),一旦这个 action 完成后,Saga 会调用另一个 action 让 reducer 进行处理。

常见用例

我们可以通过一个常见流程来说明: 用户与页面进行交互,这个交互动作会触发一个从服务端请求数据的动作(此时页面显示 loading 提示),最终我们用请求回来的数据去渲染页面的内容。 让我们为每步创建一个 action,然后用 Redux-Saga 实现一个简化的版本如下:

// saga.js
import { take } from 'redux-saga/effects'function* mySaga(){ yield take(USER_INTERACTED_WITH_UI_ACTION);
}
复制代码

这个 Saga 的函数名叫做 mySaga。它调用了 Redux-Saga effect 的 take 方法,这个方法会阻塞 Saga 的执行,直到有人调用了作为参数的那个 action,Saga 的执行也会结束,就像我们前面看到的 Generator 一样(done 变为 true)。

现在我们要让页面展示 loading 提示来响应这个 action。可以通过 put 方法调用另一个 action,然后分配 reducer 来处理,从而完成上述功能。如下:

// saga.js
import { take, put } from 'redux-saga/effects'function* mySaga(){ yield take(USER_INTERACTED_WITH_UI_ACTION);yield put(SHOW_LOADING_ACTION, {isLoading: true});
}// reducer.js
...
case SHOW_LOADING_ACTION: (state, isLoading) => {return Object.assign({}, state, {showLoading: isLoading});
}
...
复制代码

下一步是调用 call 方法,它接收一个函数和一组参数,使用这些参数来执行这个函数。我们给 call 方法传递一个请求服务端并返回一个 Promise 的 GET 函数,它会保存请求结果:

// saga.js
import { take, put, call } from 'redux-saga/effects'function* mySaga(){ yield take(USER_INTERACTED_WITH_UI_ACTION);yield put(SHOW_LOADING_ACTION, {isLoading: true});const data = yield call(GET, 'https://my.server.com/getdata');yield put(SHOW_DATA_ACTION, {data: data});
}// reducer.js
...
case SHOW_DATA_ACTION: (state, data) => {return Object.assign({}, state, {data: data, showLoading: false};
}
...
复制代码

通过调用 SHOW_DATA_ACTION 来用接收的数据更新页面。

刚刚发生了什么?

应用启动后,所有的 Sagas 都会被执行,你可以认为一直在调用 next 方法直到结束。take 方法类似于线程挂起的作用,一旦调用了USER_INTERACTED_WITH_UI_ACTION,线程就会恢复执行。

然后,我们继续调用 SHOW_LOADING_ACTION,reducer 会处理这个 action。由于 Saga 还在继续运行,call 方法会发起对服务端的请求,Saga 会在再次挂起,直到请求结束。

每次都使用

在上面的例子中,Saga 只处理了一个用户交互的 action,因为我们用 put 方法执行了 SHOW_DATA_ACTION 这个 action,然后后面就没有 yield 了(done 就是 true 了对吧?)。

如果我们希望在每次调用 USER_INTERACTED_WITH_UI_ACTION 这个 action 的时候,都会执行这一系列的 actions,我们可以用 while(true) 语句来包裹 Saga 内部的逻辑代码。完整代码如下:

// saga.js
import { take, put, call } from 'redux-saga/effects'1. function* mySaga(){
2.   while (true){
3.    yield take(USER_INTERACTED_WITH_UI_ACTION);
4.    yield put(SHOW_LOADING_ACTION, {isLoading: true});
5.    const data = yield call(GET, 'https://my.server.com/getdata');
6.    yield put(SHOW_DATA_ACTION, {data: data});
7.  }
8. }// reducer.js
...
case SHOW_LOADING_ACTION: (state, isLoading) => {return Object.assign({}, state, {showLoading: isLoading});
},
case SHOW_DATA_ACTION: (state, data) => {return Object.assign({}, state, {data: data, showLoading: false};
}
...
复制代码

这个无限循环不会造成堆栈溢出,也不会使你的应用崩溃!因为 take 方法就像线程挂起一样,mySaga 执行后会一直保持 pending 状态,直到那个 action 被触发。下次重新进入循环后,也会重复上述过程。

让我们一步步地看一下上面的过程:

  1. 应用启动,执行所有 Sagas。
  2. mySaga 运行,进入 while(true) 循环,在第 3 行挂起。
  3. USER_INTERACTED_WITH_UI_ACTION 这个 action 被触发。
  4. Saga 的线程激活,执行第 4 行,触发 SHOW_LOADING_ACTION 这个 action,然后分配的 reducer 进行处理(reducer 处理后,页面就会显示 loading 提示)。
  5. 发送一个请求到服务端(第 5 行),然后会再次挂起,直到请求的 Promise 变为 resolved,请求结果的数据会赋值给 data 变量。
  6. SHOW_DATA_ACTION 接收 data 作为参数被触发,然后 reducer 就可以使用这些数据来更新页面。
  7. 再次进入循环,回到第 2 步。

接下来

在这篇文章中,我们介绍了 Redux-Saga 相关的基本概念,展示了如何在 React 应用中使用它。下篇文章中,我会展示在实际应用中使用它获得的价值。

感谢 Yotam Kadishay 和 Liron Cohen。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。

相关文章:

CentOS下安装NetBeans集成开发环境

下载NetBeans以netbeans-7.0beta2-ml-javaee-linux.sh为例#sh netbeans-7.0beta2-ml-javaee-linux.sh之后进入安装界面(接下来和windows下几乎一样不在举例) 前提是要安装了Java 主要不要在本地远程用SecureCRT输入命令啊,要在Linux下用终端输…

我的Android进阶之旅------Android嵌入图像InsetDrawable的用法

面试题:为一个充满整个屏幕的LinearLayout布局指定背景图,是否可以让背景图不充满屏幕?请用代码描述实现过程。 解决此题,可以使用嵌入(Inset)图像资源来指定图像,然后像使用普通图像资源一样使用嵌入图像资源。 语法如…

沉痛悼念游戏开发大神毛星云

惟愿所有的“爆料”都是造谣,惟愿我们能够一起去创造并让大家都能玩到蕴藏着中国上下五千年本土文化的优质游戏大作,惟愿我们能等到你的好消息......让人难过的是,据银柿财经报道,针对近日“网传腾讯天美员工离世”的消息&#xf…

April Fools Contest 2018

这个比赛不正经,但是我可以一本正经的写代码啊 A. Quirky Quantifierstime limit per test2 secondsmemory limit per test64 megabytesinputstandard inputoutputstandard outputInputThe input contains a single integer a (10 ≤ a ≤ 999). OutputOutput 0…

如何查找僵尸进程并Kill之,杀不掉的要查看父进程并杀之

用ps和grep命令寻找僵尸进程#ps -A -ostat,ppid,pid,cmd | grep -e ^[Zz]命令注解:-A 参数列出所有进程-o 自定义输出字段 我们设定显示字段为 stat(状态), ppid(进程父id), pid(进程id),cmd(命…

PHP计划任务:如何使用Linux的Crontab执行PHP脚本(转)

我们的PHP程序有时候需要定时执行,我们可以使用ignore_user_abort函数或是在页面放置js让用户帮我们实现。但这两种方法都不太可靠,不稳定。我们可以借助Linux的Crontab工具来稳定可靠地触发PHP执行任务。下面介绍Crontab的两种方法。一、在Crontab中使用…

OpenAI 开放 GPT-3 微调功能,让开发者笑开了花

出品 | AI科技大本营(ID:rgznai100) 近日,OpenAI宣布,允许用户创建自定义版的 GPT-3。 OpenAI 表示,开发人员可以使用微调来创建针对其应用程序和服务中的特定内容量身定制的 GPT-3 模型,从而在任务和工作…

PHP----------php封装的一些简单实用的方法汇总

1、xml转换成array,格式不对的xml则返回false function xml_parser($str){ $xml_parser xml_parser_create(); if(!xml_parse($xml_parser,$str,true)){ xml_parser_free($xml_parser); return false; } else { …

PHP函数--var_dump

var_dump(PHP 3 > 3.0.5, PHP 4, PHP 5)var_dump -- 打印变量的相关信息描述void var_dump ( mixed expression [, mixed expression [, ...]] )此函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构…

Mozilla公布WebVR API标准草案

随着信息技术的迅速发展,虚拟现实(Virtual Reality,VR)技术在近些年不断完善,其应用范围也变得十分广泛。为了搭建逼真的虚拟场景,VR技术一般都需要用到大量精美的图像和复杂的动作。因此,大部分…

不到 100 行 Python 代码教你做出精美炫酷的可视化大屏

作者 |俊欣来源 |关于数据分析与可视化“碳达峰、碳中和”是2021年政府在不断强调与非常重视的事儿,那什么是“碳达峰”、什么又是“碳中和”呢?这里小编来为大家科普一下,所谓的“碳达峰”指的是在某一时间点,二氧化碳的排放不再…

JavaScript实现冒泡排序

说明 对数组进行 冒泡排序 算是比较简单的,冒泡排序也是容易理解的一种排序算法了,在面试的时候,很可能就会问到。 实现原理 数组中有 n 个数,比较每相邻两个数,如果前者大于后者,就把两个数交换位置&#…

PHP--isset()和unset()函数的用法

isset(PHP 3, PHP 4, PHP 5 )isset -- 检测变量是否设置描述bool isset ( mixed var [, mixed var [, ...]])如果 var 存在则返回 TRUE,否则返回 FALSE。 如果已经使用 unset() 释放了一个变量之后,它将不再是 isset()。若使用 isset() 测试一个被设置成…

有关任意多条曲线的拟合度算法

为什么80%的码农都做不了架构师?>>> 在股市中,经常会遇到趋势的预判。所谓趋势,即相对而言的规律化的模式识别形态。形象来讲,就是个股的一段时间内的曲线分布状况。 那么,问题来了。 我们虽然可以在少量的…

从深度学习到深度森林方法(Python)

作者 |泳鱼来源 |算法进阶一、深度森林的介绍 目前深度神经网络(DNN)做得好的几乎都是涉及图像视频(CV)、自然语言处理(NLP)等的任务,都是典型的数值建模任务(在表格数据tabular dat…

LHC大神问的矩阵转置问题

数学中线性代数中提到的矩阵转置&#xff0c;其实在我们的业务场景中也有需要的地方&#xff0c;比如LHC大神问到的这个问题 那么如何进行行列转换呢&#xff1f; 代码如下&#xff1a; <?php$arrayarray(部门1>array(费用1>100,费用2>200,费用3>300),部门2>…

不同机器互相调用WebService或者HTTP一定要telnet 测试

ping的通不一定就telnet的通 一定要#telnet 目标机器IP 目标机器端口如果一直是 Trying 目标IP那么不通如果是 Trying 目标IP Connection to 目标IP 说明通的

亮相百度WAVE SUMMIT+2021,Intel OpenVINO带来新气象

北京时间12月12日&#xff0c;百度WAVE SUMMIT2021深度学习开发者峰会在上海举办。这场属于AI的科技盛会之上&#xff0c;英特尔OpenVINO联手百度PaddlePaddle为开发者带来了一系列的技术内容&#xff0c;为开源生态构建持续合作&#xff0c;为产业进步提供新的动力。 OpenVIN…

精品德国软件 UltraShredder 文件粉碎机

出自德国的文件粉碎机&#xff0c;整合了回收站的相关操作&#xff0c;特点是兼容性好&#xff0c;支持9X以上的Win全系列&#xff08;不包括64位系统哦&#xff09;。该软件绿色免费&#xff0c;建议收藏于U盘^_^ 它和偶之前汉化的加密软件Omziff一样&#xff0c;来自XTort&am…

JavaEE 银联支付之手机控件支付-消费类交易

0. workflow app端request->后台封装参数->后台进行签名->请求银联平台->解析响应->响应需求信息 复制代码1. acp_sdk.properties ##############SDK配置文件&#xff08;证书方式签名&#xff09;################ # 说明&#xff1a; # 1. 使用时请删除后缀的…

php singleton()

common.php <?phpclass CC{private static $ins;public static function singleton(){if (!isset(self::$ins)){$c __CLASS__;self::$ins new $c;}return self::$ins;}public function EventResult($Id){return $Id;}}?>index.php <html><head><title…

2015 Multi-University Training Contest 2 1002 Buildings

Buildings Problems Link: http://acm.hdu.edu.cn/showproblem.php?pid5301 Mean: n*m列的网格&#xff0c;删除一个格子x,y&#xff0c;用矩形来填充矩阵。且矩形至少有一边是在矩阵的边缘上。 要使最大矩形的面积最小&#xff0c;求满足条件的矩形填充方式中面积最大的…

Meta 发布 Bean Machine 帮助衡量 AI 模型的不确定性

编译 | 禾木木 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; Meta 近日宣布发布 Bean Machine&#xff0c;这是一种概率编程系统&#xff0c;表面上可以更轻松地表示和了解 AI 模型中的不确定性。 在早期测试版中&#xff0c;Bean Machine 可用于通过自动的“不确…

【跃迁之路】【425天】刻意练习系列184—SQL(2018.04.06)

(跃迁之路)专栏 叨叨两句 技术的精进不能只是简单的刷题&#xff0c;而应该是不断的“刻意”练习该系列改版后正式纳入【跃迁之路】专栏&#xff0c;持续更新刻意练习——MySQL 2018.04.02 题目描述 DROP TABLE IF EXISTS test1;CREATE TABLE test1 (id int(11) NOT NULL AUTO_…

安利一个超好用的 Pandas 数据挖掘分析神器

作者 |欣一来源 |Python爱好者集中营今天小编继续来给大家介绍一款用于做EDA(探索性数据分析)的利器&#xff0c;并且可以自动生成代码&#xff0c;帮助大家极大节省工作时间与提升工作效率的利器&#xff0c;叫做Bamboolib。大家可以将其理解为是Pandas的GUI扩展工具&#xff…

PHP魔术常量

PHP 向它运行的任何脚本提供了大量的预定义常量。不过很多常量都是由不同的扩展库定义的&#xff0c;只有在加载了这些扩展库时才会出现&#xff0c;或者动态加载后&#xff0c;或者在编译时已经包括进去了。 有七个魔术常量它们的值随着它们在代码中的位置改变而改变。例如 _…

vim 打开Linux下文件每一行后面都有^M的样式

由于服务器不是我一个人在操作&#xff0c;在修改apache配置文件时发现了一个很奇怪的问题&#xff0c;vim编辑打开配置文件发现后面都有一个^M的标记 虽然不会影响服务的运行&#xff0c;但总感觉不对劲&#xff0c;所以在此我尝试用替换的方式来设置它 :%s/\^M//g 虽然也成功…

所有类是object的子类,但是又可以继承一个其他类解析

所有类的祖宗是object&#xff0c;所有类只能有一个父亲。Java的单继承指的是一个类不能有多个父亲&#xff0c;而C就能有好多父亲。举个例子&#xff1a;如果A 没有继承任何类&#xff0c;那他的类层次关系默认是 A -- Object如果A 继承了类B&#xff0c;那他的类层次关系变为…

Smarty中文手册,Smarty教程,Smarty模板的入门教材

Smarty中文手册,Smarty教程,Smarty模板的入门教材首先&#xff0c;这份Smarty中文手册的翻译工作是由喜悦国际村村民自发组织的&#xff0c;不代表任何人的意见和观点。对他们的无私奉献精神&#xff0c;我们表示感谢&#xff0c;他们为Smarty模板的普及作出了重大的贡献&#…

380万播放量,也许是全网最火的机器学习视频

“秋名山上行人稀&#xff0c;常有车手较高低。如今无人车当道&#xff0c;全是 AI 老司机。”且问 AI 老司机表现如何&#xff1f;可灵活转弯&#xff0c;控速自如&#xff1a;可行云流水&#xff0c;沿最优路线过弯&#xff1a;更可多次打圈&#xff0c;绕多少下也不在话下&a…