什么是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如何改变可预测性
可预测性
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应用中的状态。我们来了解一下!
更多资料
如何在Redux的store和React的状态之间做出选择?(How
纯函数
什么是纯函数?
纯函数是 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?)
数组的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 来更新其数据存储。 我们将在下一课中检查它们!