JavaScriptJava Web架构设计Flutter学习教程

为何要使用Redux

2017-12-01  本文已影响9680人  ccchaixr

什么是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

上一篇下一篇

猜你喜欢

热点阅读