现代应用必须比以往做得更多,相应地也更加复杂——内部和外部都是如此。开发者们早就意识到缺乏一致设计的复杂应用的增长所造成的混乱。意大利面条似的代码不仅没有乐趣,还会拖慢开发者的开发进度,进而拖慢业务单元的进度。还记得上一次在满是一次性解决方案和jQuery插件的大型代码库中的工作吗?估计这不会有趣。为了对抗混乱,开发者们开发了MVC(模型-视图-控制器)这样的范式来组织应用的功能并指导开发。Flux(及其扩展Redux)与此相同,都是为了帮助开发者处理应用中不断增加的复杂性。
如果不是特别熟悉MVC范式,也不必担心,在本书中我们不会花太多时间讨论它。但为了便于比较,在讨论Flux和Redux之前,先简单讨论一下MVC。下面是一些基础知识。
虽然本章重点讨论的范式(Flux和Redux)与这些概念大相径庭,但其目标仍是帮助开发者创建可伸缩的、合理的和有效的应用架构。
Redux的起源和设计要归功于Facebook内部流行的一种称为Flux的模式。如果熟悉Ruby on Rails和其他应用框架所使用的流行MVC模式,那么Flux可能与你习惯的模式有所不同。Flux没有将应用的各个部分分解为模型、视图和控制器,而是定义了若干不同部分。
图10-1展示了Flux的概览。
图10-1 一个简单的Flux概览
如图10-1所示,在Flux模式中,action是从视图中创建的(可能是用户点击了某个东西),然后dispatcher处理传入的action,之后将action发送到适当的store中以更新状态。状态变化后,通知视图应该使用新数据(如果可以应用的话)。请注意这与典型MVC风格的框架有何不同,在MVC风格的框架中,视图和模型(如此处的store)都能够更新彼此。这种双向数据流不同于Flux架构中典型的更为单向的数据流。另外,请注意这里缺少中间件:尽管可以在Flux中创建中间件,但它不像在Redux中那样是一等公民,因此我们在这里省略了它。
如果之前开发过MVC风格的应用,其中一些内容听起来很熟悉,但数据流转方式可能就不是这样了。如前所述,数据在Flux范式中更多的是单向流动,这与MVC类型的实现倾向于使用的双向方式不同。这通常意味着应用中数据流没有单一的来源;系统的许多不同部分都有权修改状态,而且状态通常分散在整个应用中。这种方式在很多情况下都能很好地工作,但在较大的应用中,调试和使用时可能会令人费解。
想象一下,在一个中到大型的应用中,这会是什么情形。假设有一组模型(用户、账户和身份验证),它们与自己的控制器和视图相关联。在应用中的任何地方,都很难确定状态的确切位置,因为状态分布在应用的各个部分(可以在之前提到的3个模型中的任何一个中找到关于用户的信息)。
对较小的应用来说,这可能未必是问题,甚至可以在较大的应用上也能很好地工作,但在大型客户端应用中,它可能变得更加困难。例如,当需要在50个不同的位置修改模型的使用并且有60个不同的控制器需要了解状态的更改时,会发生什么情况?让事情变得更复杂的是,视图有时在某些前端框架中表现的就像模型一样(因此状态更为分散了)。数据的真实来源在哪里?如果它分散在视图和许多不同的模型中,并且所有这些都处于中等复杂的设置中,那么在心里跟踪所有内容将是很困难的。这还可能导致应用状态不一致,这会引发应用bug,因此这不只是一个“只有开发人员才面对”的问题,最终用户也会受到直接影响。
这之所以困难的部分原因在于,人们通常不善于推断随时间发生的变化。为了真正理解这个问题,想象脑海中有一个棋盘。在脑子里保持一张甚至几张棋盘的快照并不难,但能跟踪20个回合的每个棋盘快照吗?30回合呢?整局对弈呢?正因为在脑海中跟踪数据随时间的异步变化很困难,所以我们应该构建更易于我们思考和使用的系统。例如,考虑调用远程API并使用其数据更新应用状态。对数量较少的情况来说这很简单,但如果需要调用50个不同的API服务器端点并且需要跟踪进入的响应,与此同时用户仍在使用应用并进行可能引起更多API交互的改变时,那么会怎么样?很难在脑海中将它们梳理清楚并预测变化的结果。
你可能已经注意到React和Flux之间的一些相似性。它们都是相对较新的一种构建用户界面的方式而且都旨在改进开发人员使用的心智模型。在这两种方式中,变化应该很容易推断,并且开发者应该能够以一种增强而不是碍事的方式构建UI。
Flux在实际代码中是什么样子呢?它主要是一个范式,所以有很多库实现了Flux的核心思想。这些库在实现Flux的方式上略有不同。Redux也一样,尽管它独特的Flux风格已经获得了最多用户和关注。其他Flux库包括Flummox、Fluxxor、Reflux、Fluxible、Lux、McFly和MartyJS(尽管在实践中与Redux相比这些库使用得很少)。
也许Redux是实现Flux背后思想的使用最广泛且最知名的库。Redux这个库以稍加修改的方式实现了Flux的思想。Redux的文档将其描述为“JavaScript应用的可预测状态容器”。具体而言,这意味着它通过自己的方式将Flux的概念和思想付诸了实践。
确定Flux的确切定义在这里并不重要,重要的是我将介绍Flux和Redux范式之间的一些重要区别。
对你来说这些可能只是些细微差别,没关系——你的目标是学习Redux,而不是“找不同”。图10-2展示了Redux架构的概览。我们将深入每个不同的部分,探索它们如何工作,并为你的应用开发一个Redux架构。
图10-2 Redux概览
如图10-2中所示,action、store和reducer构成了Redux架构的主体。Redux使用一个中心化的状态对象,它以特定的、确定的方式进行更新。当开发者想要更新状态时(通常是由于单击之类的事件),一个action被创建出来。action具有特定reducer会处理的类型。处理给定action类型的reducer会生成当前状态的副本,使用来自action的数据对其进行修改,然后返回新状态。当更新store时,视图层(此处是React组件)可以监听更新并相应地作出响应。还要注意,图中的视图只是从store中读取更新——它们并不关心与其通信的数据。React-redux库会在store更改时将新的props传递给组件,但视图仍旧只是接收和显示数据。
Redux是一种应用架构范式,它也是一个可安装的库。这是Redux超过“原始”Flux实现的一个方面。Flux范式有非常多的实现(如Flummox、Fluxxor、Reflux、Fluxible、Lux、McFly和MartyJS),它们都有不同程度的社区支持和不同的API。Redux拥有强大的社区支持,但Redux库本身的API却十分小巧而强大,这帮助它成为最受欢迎且最受倚重的React应用架构库之一。事实上,Redux与React一起使用的情况非常常见,以至于两个核心团队经常彼此交流,以确保兼容和知晓特性。有些人甚至同时身处两个团队,所以两个项目之间有着很好的可见性和良好的沟通。
为了设置好Redux从而使用它,需要做一些工作。
Redux被设计为可预测的,这使得创建令人惊异的调试工具变得容易。Dan Abramov和其他致力于Redux和React库的工程师已经开发出了一些处理Redux应用的强大工具。因为Redux中的状态是以可预测的方式变化的,所以有可能用新方式进行调试:开发者可以跟踪应用状态的单个变化,检查变化之间的差异,甚至可以回退和重放应用状态随时间的变化。Redux Dev Tools扩展可以让使用者完成所有这些工作甚至更多,而且其被打包为浏览器扩展进行分发。图10-3快速窥探了Redux Dev Tool拥有的功能。
图10-3 Redux Dev Tools扩展将来自于Dan Abramov的流行的Redux Dev Tools库打包成一个方便的浏览器扩展。有了它,就可以回退和重放Redux应用,逐个查看变化,检查状态变化之间的差异,在一个区域检查整个应用的状态,生成测试样板,等等
安装好扩展后,应该能在浏览器的工具栏中看到新开发工具的图标。截止行文期间,它仅会在开发模式下检测到Redux应用实例时才变为彩色的,所以如果访问的应用或网站没有使用Redux,扩展就不会起作用。不过一旦配置好应用,就会看到图标变成彩色的,并且点击它会打开这个工具。
本文摘自《React实战》
本书指导读者像专家一样思考用户界面(UI),并教读者用React构建它们。本书非常实用,配有很多可实际操作的示例,让读者快速上手。本书的目标是让读者掌握渲染、生命周期方法、JSX、数据流、表单、路由、与第三方库集成和测试等核心概念,并且帮助读者利用书中介绍的应用设计理念推动应用的流行。在学习将React集成到全栈应用的过程中,读者还可以探索通过Redu**行状态管理和服务器端渲染,甚至可以接触到用于移动UI 的React Native。本书专门写给熟悉HTML、CSS 和JavaScript 的开发者。
本书主要内容
● 从头开始使用React。
● 用组件实现路由系统。
● 在Node.js中进行服务器端渲染。
● 使用第三方库。
● 测试React组件。