为何要使用Redux

什么是Redux它为什么存在

Redux专门用于管理状态

Redux官方文档对Redux的定义如下:

一个面向JavaScript应用的可预测状态容器。

你可能会问,“如果React已经在为我的应用管理前端状态,为何还需要Redux?”

使用Redux的主要优势之一是它可以帮你处理应用的共享状态。如果两个组件需要访问同一状态,该怎么办?这种两个组件同时需要访问同一状态的现象称为“共享状态”。你可以将该状态提升到附近的父组件,但是如果该父组件在组件树中向上好几个组件的位置,那么将状态当做属性向下一个一个地传递,这项工作很快就会变得乏味。此外,在该父组件和该子组件之间的组件甚至根本不需要访问该状态!

在构建网络应用时,Redux不仅使我们能够以有条理的方式存储数据,而且使我们能够在应用的任何位置快速获取该数据。只需告诉Redux到底哪个组件需要哪个数据,它就会为你处理后续一切工作!

借助Redux,你可以控制状态改变的时间、原因和方式。

Store:单一数据源

Redux的基本原则之一是存在单一数据源:Store。也就是说,Store包括应用的全局状态,全存储在一个对象树中。

只有单个状态树,对于应用的很多方面都有好处。假设在构建应用时尝试实现撤消/重做功能。如果所有状态都存储在一个树(单一数据源)中,则实现起来比数据分散在多个组件中简单多了。状态集中到一个位置后,调试和检测过程也会简单很多!

为了保持这种单一数据源特性,Redux制定了几条规则,确保一切尽在掌控。规则一:Redux应用中的状态是只读的,即Redux状态不可变。例如,React组件不能直接写入Redux状态,而是发出intent来更新状态。

实际上,只有叫做reducer的纯函数能够更改状态。暂时别担心这些概念,我们会在下节课深入讲解的!

练习题

关于Redux的哪些描述是正确的?请选中所有适用项:

所有React应用都需要Redux

Redux可以用于其他视图库

Redux实现的是单个状态树,使调试过程更简单

视图和网络回调应该直接写入Redux状态

Redux状态通常保存在多个Store中

答案:2、3。Redux可以用于React之外的其他项目!Redux的确会实现单个状态树。将所有数据放在一个位置并通过一个界面进行维护后,调试和处理数据变得更加简单。


随着单页面应用变得越来越复杂,正确地管理状态这一需求更加重要。例如,除了管理表格状态(例如《React基础知识》课程中的Contacts应用)等数据外,应用可能还需要管理:

服务器响应

缓存的数据(例如用户)

尚未保存到服务器上的本地数据

除此之外,UI状态也越来越复杂。同一应用可能还需要跟踪:

当前路由

当前选择的标签页

页码控件

Redux便因此而生,它专门用于管理上述所有这些内容。创建者Dan Abramov在2015年根据Flux架构创建了Redux,并从Elm编程语言中汲取了经验。从那以后,Redux变得越来越受欢迎,每月的下载量达到数百万。

总结

Redux是一个JavaScript库,用于管理应用的前端状态。Redux并非React应用的必须条件,但是随着网络应用的复杂性越来越高,状态管理不当可能会导致bug。Redux应用中的全局状态存储在单一数据源store中。因为状态的更新受到严格控制,使得Redux非常具有可预测性。实际上,开发人员喜欢Redux的主要原因之一就是它的可预测性。我们来看看背后的原因!

更多资料

Redux文档中的Motivation 部分

Redux的三大原则

GitHub上的Redux

npm上的Redux

Redux如何改变可预测性

可预测性

Redux以多种方式提高了Web应用程序的可预测性。我们从上一节(什么是Redux /它为何会存在?)中看到,数据被合并到一个集中的位置:store。组件不能直接修改store中的数据;相反,他们必须请求访问这些数据。此外,store如何更新也有严格的规定。

因此,你总是知道状态来自哪里(store),以及允许哪一个唯一实体触发更新(action)到该状态。

另一种看待Redux的方式是它提供了一个严格的单向数据流。我们将在下一课中深入探讨这些独特的元素,但是主要原则与React的主要原则并没有太大的区别。

单向数据流概述

回顾React的核心功能之一,单向数据流:


数据从父组件向下流到子组件。数据更新被发送到父组件,父组件进行实际的更新。

在上图中,数据存储在父组件中。如果子组件也需要使用该数据,该数据可以向下传递给子组件。任何更新都向上发送给父组件,由父组件做出更新,更新后的数据再向下发送给子组件。

React的单向数据流功能很强大,但是当处理深度嵌套的组件结构时,就会出现问题:


例如这个嵌套组件结构,其中属性必须经由很多组件向下传递,才能显示出来。

对于深度嵌套的组件结构,数据必须途经所有中间组件才能向下传递到目标对象!

练习题

以下哪些关于store的描述是正确的?请选中所有适用项。

store使用单向数据流

store包含所有/大部分应用数据

store是普通的JavaScript数组

store制定了严格的store更新规则

答案:1、2、4

总结

Redux以多种方式提高可预测性:

它将大多数数据整合到一个位置

组件必须请求访问数据

store中的数据流向一个方向

store更新有着严格的规则

Redux秉承了React采用的单一数据流结构。我们将在下一课中,深入讲解这部分内容!

更多资料

Redux文档的Data Flow部分

Redux Store和组件状态

store代表的是单一数据源;它会存储应用的全局状态。

哪个状态?在何处?

Redux是一个强大的网络应用状态容器,但是并没有硬性规定所有状态都必须包含在一个Redux store中。实际上,也可以将某些数据存储在(React)组件状态中。最终由你来决定哪种方式最适合你的应用,当然你也可以遵守一些常用的惯例:

Redux Store

通常,如果状态是共享的,并且可在整个应用中访问,则应存储在store中。示例包括:

缓存用户信息

电子邮件草稿

组件状态

另一方面,如果涉及的是更加“本地”的数据,或者处理的状态不影响其他组件,则更适合使用组件的状态:

表格输入

当前标签页切换

下拉菜单的打开/关闭状态

无论选择哪种方式,都要确保它适合你和你的应用。正如Dan Abramov在Redux文档中所提到的:

没有固定的标准答案...作为开发人员,你需要判断在你的应用中应使用哪些状态,以及状态应该储存在哪里。你需要权衡利弊,找到平衡。



Redux状态是只读的

另外要提的一点是,Redux store中的状态是只读的,实际上,这只是Redux的三大基本原则之一。这样设计的好处是:

增强了可预测性和可靠性

避免产生副作用(下个部分将详细介绍!)

阻止外部文件修改state

所有对state的改动都被集中于一个地方,并且被严格地依次触发

更改state的唯一方式是派发相应的action,以描述所需的更改。暂时不用担心这些概念;我们将在下个部分详细讲解!

总结

虽然Redux提供了单一数据源,但是完全可以在组件的内部状态中存储一些数据。对于store中的全局状态,Redux对何时及如何更新状态制定了严格的限制条件。其中一个限制条件是只有纯函数可以更新Redux应用中的状态。我们来了解一下!

更多资料

状态是只读的(State is Read-Only)

如何在Redux的store和React的状态之间做出选择?(How

状态管理(Organizing State)

纯函数

什么是纯函数?

纯函数是 Redux 应用中,更新状态的必要手段。纯函数的定义是:

对于同一参数,返回同一结果

完全取决于传入的参数

不会产生副作用

我们来看一个纯函数square()的示例:

// `square()` 是一个纯函数

const square = x => x * x;

square()是一个纯函数,因为只要每次传入相同的参数,其输出的值都一样。结果不取决于任何其他值,我们可以肯定只会返回该结果,没有副作用(稍后将详细介绍这一概念!)。

另外,我们再看一个非纯函数calculateTip()的示例:

// `calculateTip()` 是一个非纯函数

consttip Percentage =0.15;

constcalculateTip = cost => cost * tipPercentage;

calculateTip()计算并返回了一个数值。但是,它取决于位于该函数外部的变量 (tipPercentage) 来生成该值。因为calculateTip()不符合纯函数的条件之一,所以是非纯函数。我们可以通过把外部变量tipPercentage当做第二个参数传入该函数,将该函数转换为纯函数:

constcalculateTip = (cost, tipPercentage =0.15) => cost * tipPercentage;

没有副作用

纯函数的条件之一是不产生副作用。副作用是指函数对其外部世界产生影响,包括:

发出 HTTP 调用

改变外部状态

检索今天的日期

Math.random()

向控制台输出消息

向数据库中添加数据

使用纯函数

纯函数是函数式编程的核心概念。除了避免数据突变和副作用之外,纯函数还与组件的概念非常契合。

首先,纯函数本质上就是模块化的,这使它更容易被测试。由于当参数相同时,纯函数总是产⽣相同的结果,你不必担⼼应用其他部分的数据受到影响。在调试期间,这将给予明确定义的额外控制点。

此外,纯函数使代码更好维护。纯函数不会产生副作用。这意味着你在重构应用时,纯函数不会对其外部内容产生任何不利影响。

尽管使⽤纯函数会为你的应⽤带来诸多好处,你仍然可以选择将纯函数与非纯函数一起使用。使用非纯函数并不一定意味着“糟糕的编程方式”。例如,使用事件处理程序更新 DOM 的按钮就不适合使用纯函数,因为事件处理程序会更新 DOM(即产生副作用!)。

使用纯函数可以帮助你提高代码质量,在构建应用时记住这一点将使你成为更优秀的程序员。

总结

纯函数并不是 Redux(甚至 JavaScript)独有的,但是它们的确支持在应用中实现可预测性。在下节课,我们将深入学习叫做reducer的纯函数如何返回应用的新状态。Reducer 基于 Array 的reduce()方法,我们来了解下!

更多资料

什么是纯函数?(What is a Pure Function?)

什么是函数式编程?(What is Functional Programming?)

纯函数示例(The Case for Purity)

数组的Reduce()方法


Array 的.reduce()方法

.reduce()的核心概念是传入大量数据,但只返回一个值。.reduce()是一个高阶函数,这意味着它可以将一个函数(比如回调函数)作为参数传入。

高阶函数 

我们在《React 基础知识》中见到的.map()和.filter()方法也是高阶函数!这两个函数都可以将回调函数作为第一个参数传入。

为了了解.reduce()的强大功能,来看看下面这个iceCreamStats数组, 它表示每个小组成员吃掉的冰激凌加仑数。

const iceCreamStats = [  {    name:'Amanda',    gallonsEaten:3.8},  

{    name:'Geoff',    gallonsEaten:5.2},  

{    name:'Tyler',    gallonsEaten:1.9}, 

 {    name:'Richard',    gallonsEaten:7923}];

如果我们要查看吃掉的冰激凌总量,我们这太没有挑战性了!我们希望将此数据reduce(缩减) 为单个数字,而这正是.reduce()方法的作用!我们看看如何做到这一点!

这就是我们刚刚使用的.reduce()代码:

iceCreamStats.reduce( 

(accumulator, currentValue) =>

 {returnaccumulator + currentValue.gallonsEaten;},0);



总结

.reduce()是一个功能强大的方法,它允许你将大量数据减少为单个值。 Redux 利用这个相同的原理,使用 reducer 来更新其数据存储。 我们将在下一课中检查它们!

Array.prototype.reduce on MDN

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,552评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,666评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,519评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,180评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,205评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,344评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,781评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,449评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,635评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,467评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,515评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,217评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,775评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,851评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,084评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,637评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,204评论 2 341

推荐阅读更多精彩内容