这一节将介绍 React 的核心应用架构模式 Flux,包括内容:

  • Flux 介绍

  • MVC 架构之痛

  • Flux 的理解

  • Flux 相关库和工具介绍

  • Flux 与 React 实例

最后我们将会把之前的 TODOMVC 改为 Flux 的架构。

1.6.1 Flux 介绍

简单来讲,Flux 是 Facebook 引入到 React 中的一种前端架构,通过定义其核心单向数据流的方式,让 React 应用更加健壮。同时,这种应用架构也具有普适性,可以应用到其他任意前端项目中,甚至可以应用到客户端应用开发中,也就是说 Flux 更应该叫做一种架构模式(Pattern)。

1.6.2 MVC 架构之痛

在详细介绍 Flux 之前,我们先来看看传统的前端 MVC 架构以及其带来的问题。

MVC 的实现可能有很多种方式,比较灵活,但基本本质不会改变,只是三者间的数据传递方向可能会改变,即便是 MVP 模式也只是 MVC 的变种,所以为了统一我们且以下图的 MVC 方式来讨论。

概念

  • Model: 负责保存应用数据,和后端交互同步应用数据

  • View: 负责渲染页面 HTML DOM

  • Controller: 负责连接 View 和 Model , Model 的任何改变会应用到 View 中,View 的操作会通过 Controller 应用到 Model 中

  • 关系:Model, View, Controller 都是多对多关系。

流程

以 TODOMVC 为例子用户添加一个 todo 的交互流程:

View -> Action -> Controller -> Model -> View

  1. View -> Action: 添加按钮事件或者 input 输入的提交事件

  2. Action -> Controller: 控制器响应 View 事件

  3. Controller -> Model: 控制器依赖 Model, 调用 Model 添加 todo

  4. Model -> View: View 监听 Model 的改变添加 todo 事件,在 HTML 中添加一个新的 Todo 视图

问题

对于新增一个 todo ,需要编写一个视图渲染处理函数,函数内添加新项目到列表中。同理对于删除一个 todo,也会有一个处理函数。当业务逻辑变多过后,可能有很多模型需要做增删改的功能,与之对应的就是我们需要精心构建这么多的渲染处理函数。 这种局部更新模式是高性能的关键所在,但问题是:

  1. 更新逻辑复杂,需要编写大量的局部渲染函数

  2. 问题定位困难,页面的当前状态是有数据和这些局部更新函数确定的

如何解决

如果渲染函数只有一个,统一放在 App 控制器中,每次更新重渲染页面,这样的话:

  1. 任何数据的更新都只用调用重渲染就行

  2. 数据和当前页面的状态是唯一确定的

重渲染也有弊端,会带来严重的性能问题,重渲染和局部渲染各有好坏,对 MVC 来说这是一个两难的选择,无法做到鱼和熊掌兼得。

那如何才能兼顾两种模式的优点?

1.6.3 Flux 架构

通过 React + Flux 就可以完美解决 MVC 的问题。

  1. 重渲染: 在 React 中每次渲染都是重渲染,且不影响页面性能,是因为重渲染的是 Virtual Dom。这就意味着完全不用去关系重渲染问题,增删改的渲染都和初始化渲染相同入口

  2. 数据和状态一致性: Store 的数据确定应用唯一的状态

简单来说在 Flux 架构中直接剥离了控制器层,MVC 架构变成了 MV + Flux 架构。

概念

单向数据流

这是 Flux 架构的核心思想,重上面的图中可以看到,数据的流向从action 到 view 的一个单向流。

Action

Action 可以理解为对应用数据修改的指令,任何修改应用数据的行为都必须需通过触发 action 来修改。Action 可以来自于 View,也可以来自服务端的数据更新。

Action Creator:

为了抽象 Action ,提供一些辅助的语义化的方法来创建 Action,这些辅助方法叫做 Action Creator。

Stores

应用的数据中心,所有应用数据都存放在这里控制,同时包含数据的控制行为,可能包含多个 store

Dispatcher

action 的控制者,所有 action 都会通过 dispatcher,由 dispatcher 控制 action 是否应该传入到 store 中,Dispatcher 是一个单例。

View

页面的视图,对应 React 的 Component, 视图可以触发 action 到 dispatcher。

需要区别出一种叫控制器 View(Controller View)的类型,这种 View 可以知晓 store 数据,把 store 数据转化为自身的状态,在将数据传递给其他 view 。 并且可以监听 store 数据的改变,当 store 数据改变过后重新设置状态触发重渲染。 可以将控制器 View 对应 MVC 中的控制器,但是差别很大,控制器 View 唯一多做的事情就是监听 store 数据改变,没有其他任何业务处理逻辑。

流程

同样以 TODOMVC 的添加 todo 为例,Flux 中的流程为:

View -> Action(Action Creator -> Action) -> Dispatcher -> Store -> Controller View -> View

  1. View -> Action: 添加按钮事件或者 input 输入的提交事件,View 中将事件转化为 action, action 由 Action Creator 创建。

  2. Action -> Dispatcher: action 统一由 Dispatcher 分配

  3. Dispatcher -> Store: Dispatcher 分配 action 到 Store

  4. Store -> Controller View: 控制器 View 监听 store 的数据改变,将数据转化为自身属性

  5. Controller View -> View: 数据改变自动重渲染所有视图

对比

  1. 渲染策略: 数据改变 Flux 自动渲染,MVC 手动编写更新函数

  2. 事件触发策略: Flux 中所有 action 交给 dispather 分配,MVC 中交给对应的控制器分配

Flux 在核心策略上的不同是解决 MVC 架构问题的关键

1.6.4 理解 Flux 架构

Flux 架构是非常优雅简洁的,合理利用了一些优秀的架构思维

分而治之(Divide And Conquer)

数据的处理过程是 Store -> Controller View -> View。 所有数据来自于 Store,页面的渲染层级为 Store 将数据传入 Controller View, 再由 Controller View 传入子 View , 一直到 View 的叶子节点。

这个是一个典型的分而治之策略,将大的页面拆分为小的模块,再由小的模块拆分为小的组件,具体组件负者组件自身的问题,所有子组件都是自私的,不用关心“大家”,只用关心“小家”。

合而治之 - 中心化控制

Flux 把所有的 View 都视作愚民,Store 视作资源的拥有者为统治者,统治者需要提供资源(数据)给平民,但是如果平民企图对资源修改(Mutation),必须得先通知给统治者,让统治者决定是否做处理。

我们为 Flux 中的概念分配角色

  • View: 平民

  • Action: 资源修改操作

  • Dispatcher: 审核官

  • Store: 统治者

一个企图修改资源的操作可以描述为:

View Require Mutation -> Action -> Dispatcher -> Store -> Mutate Handler

平民提交 Mutation 请求,由审核官控制,审核通过后递交给统治者,统治者再分配给亲信做资源 Mutation

合而治之的策略也等于中心化控制策略, 作为统治者既要懂得放权利(资源的分配),也要懂得控制权利(资源的修改),这种收缩自如的合理性是 Flux 简洁的根本。

同时这种思维带来的优点如下:

  1. View 的独立性和简单性:View 自身的逻辑简单,不需要知道太多事情,只关心上级传来的数据,这种模式使得 View 是低耦合的,简洁的。

  2. 高可维护性:中心化控制知道所有对资源的操作,如果发生 bug, 可以很快定位问题

函数式编程思想

在 Flux 中数据的单向流动依赖于 View 的确定性,相同的数据传入相同的组件,得到的结果必然要相同,这是函数式编程的思想。

函数式编程中的纯函数(Pure Function)定义如下:

纯函数是这样一种函数,即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用

如:

// 纯函数,相同的输入必定有相同的输出function pure(a, b, c) {
return a + b + c;
} // 非纯函数,我们永远无法确定 this.a 会变成什么function notPure(b, c) {
return this.a + b + c;
}

为了保证组件也能做到 “纯函数” 的特性,相同的属性会得到相同的渲染结果。 在写 React 组件的时候尽量准守一下约定:

  1. 尽量使用无状态组件

  2. 除了控制类组件以外其他组件避免使用组件状态

  3. 可以通过属性计算出来的状态不要用状态来表示

  4. 组件的渲染避免外部依赖,按照纯函数的方式写

函数式的优点也是无副作用组件的优点:

  1. 无耦合,可移植性强: 组件可重用性高

  2. 可测试性高:组件无依赖,可以很容易的单独测试组件

1.6.5 Flux 生态

上面已经讲过 Flux 更应该算是 Facebook 提出的一种前端架构模式,而根据这种理念的 Flux 实现有很多,以下是 github star 数较高的一些实现:

  1. Facebook 官方实现

  2. Redux 目前认可度最高的实现

  3. refluxjs

  4. alt

  5. fluxxor

后面我们会在第四章中专门讲解 Redux 与 React 的应用。

1.6.6 Flux 与 React 实例

1.6 flux介绍的更多相关文章

  1. 【11】react 之 flux

    Flux 是 Facebook 使用的一套前端应用的架构模式.React 标榜自己是 MVC 里面 V 的部分,那么 Flux 就相当于添加 M 和 C 的部分. 1.1.  Flux介绍 Flux并 ...

  2. Flux和ExtJS MVC框架的异同点介绍

    Flux是Facebook在现有MVC框架数据流动复杂,难以设计和维护大型的前端应用的情况下设计的一种新的数据架构协议.叫做协议是因为Flux本身就像MVC一样,规定了一种机制,但是Facebook提 ...

  3. flux架构的详细介绍和使用!

    结构分为四个 视图 view动作 action派发器 dispatcher数据商店 store 流程: 用户操作视图 视图(view)发送动作(action)到派发器(dispatcher) 由派发器 ...

  4. redux+flux(一:入门篇)

    React是facebook推出的js框架,React 本身只涉及UI层,如果搭建大型应用,必须搭配一个前端框架.也就是说,你至少要学两样东西,才能基本满足需要:React + 前端框架. Faceb ...

  5. 【原】flux学习笔记

    最近React(web/native)依旧如火如荼,相信大家都跃跃欲试,入职新公司,现在的团队也开始在React领域有所尝试. 2016年应该是React 逐渐走向成熟的一年.之前在原来公司搞不懂的问 ...

  6. Flux Demo解析

    最近学习了阮一峰老师的博文 "Flux入门教程",博文中详细介绍了Flux框架和Controller view模式,并提供了Demo,受益匪浅. 现特参考阮老师的Demo,绘制了一 ...

  7. 使用 React 和 Flux 创建一个记事本应用

    React,来自 Facebook,是一个用来创建用户界面的非常优秀的类库.唯一的问题是 React 不会关注于你的应用如何处理数据.大多数人把 React 当做 MV* 中的 V.所以,Facebo ...

  8. Flux demo

    Flux demo Introduction flux应用架构如下图所示,本文并不是讲述怎么立即做一个酷炫的应用,而是讲述如何依照这种框架,来进行代码的组织.我们先把这个流程转述为文字:抛开与webA ...

  9. Flux是一个Facebook团队的前端开发架构

    Flux是一个Facebook团队的前端开发架构 Flux introduction 本文组成: React 官方文档翻译 相关实践心得. 内容上是Flux的介绍,例子将会在以后写出.一旦稍微多了解一 ...

随机推荐

  1. linux(Ubuntu) 搭建LAMP环境

    1.更新源 sudo apt- get update 2.安装常用软件 SSH.Vim.Git.Tree ①SSH sudo apt-get install openssh-server 管理命令:s ...

  2. POJ 1797 Heavy Transportation (Dijkstra)

    题目链接:POJ 1797 Description Background Hugo Heavy is happy. After the breakdown of the Cargolifter pro ...

  3. upc组队赛6 Bumped!【最短路】

    Bumped! 题目描述 Peter returned from the recently held ACM ICPC World finals only to find that his retur ...

  4. \r\n\t 转义字符

    https://www.cnblogs.com/lsqbk/p/10259044.html https://www.cnblogs.com/f158w058/p/6548073.html 文件中的换行 ...

  5. spark textFile读取多个文件

    1.spark textFile读取File 1.1 简单读取文件 val spark = SparkSession.builder() .appName("demo") .mas ...

  6. SqlServer 跨库访问

    同实例跨库 只需要 库名.dbo.表 dbo可省略 如: use Test select * from rdrecords select * from oa.dbo.UserInfo 不同实例与不同i ...

  7. 当vue页面异步加载的数据想在页面上渲染怎么办

    <template> <div class="test"> <div v-for="(item, index) in arr" : ...

  8. HTML + CSS (下)【更新中】

    弹性盒子: 定义:弹性盒子模型是css3中新提出的一种布局方案.是一种为了应对针对不同屏幕宽度不同设备的一整套新的布局方案. 主要是对一个容器中的子元素进行排列.对齐和分配空白空间的方案的调整. 新旧 ...

  9. Node.js中的fs文件系统

    fs.stat 检测是文件还是目录 fs.mkdir 创建目录 fs.writeFile 创建写入文件 fs.appendFile 追加文件 fs.readFile 读取文件 fs.readdir 读 ...

  10. Java中super关键字的位置

    1.子类的构造函数如果要引用super的话,必须把super放在函数的首行. 例如: class Base  { Base()  {  System.out.println("Base&qu ...