- 从最开始学习
React
就接触到Flux
架构,接着前端组件化框架都涉及到Flux
概念,例如Vue.js
中的Vuex
。一直以来Flux
都不是很好理解,但俗话说实践出真知,只有在真正的项目场景上使用过了,才知道一个架构概念为什么要如此设计,可以带来什么样的好处。
Flux定义
-
Flux
是一种架构思想,用来解决软件结构问题。 -
Flux
将一个应用分成四个部分:
View: 视图层
Action(动作):视图层发出的消息(比如mouseClick)
Dispatcher(派发器):用来接收Actions、执行回调函数
Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面
用一张流程图来表示:

- 在
Flux
中,数据是单向流动的:
- 用户访问 View
- View 发出用户的 Action
- Dispatcher 收到 Action,要求 Store 进行相应的更新
- Store 更新后,发出一个"change"事件
- View 收到"change"事件后,更新页面
一个实践和理解
- 上面的定义在网上一搜就有。但相信很多人一开始和我一样,定义看的懂,但并不理解为什么要这么做,这样做可以带来什么好处?接下来试着用一个在实际项目中的场景来说明一下。
业务场景

- 界面有两个大区域组成:
- 顶部
Header
:显示当前操作的公司名称- 下部
Workplace
:主要功能工作区,包含一个Tab
组件。
-
Workplace
中第一个Tab
是公司选择功能:填写公司名称,点击确定之后输入的公司名称成为全局变量,并且显示在Header
中。 - 在其他Tab页面中可以获取到当前设定的公司名称值。
结构设计
- 使用现在也非常流行的
Vue.js
+Vuex
来解决这个问题。 - 有一些前端模块化框架经验的同学应该很容易想到:
- 把两个主区域(
Header
,Workplace
)分成两个模块(两个.vue
文件)。Tab
中的N个功能页面也对应着N个模块(N个.vue
文件)。- 使用
route
实现点击Tab
页在Workplace
中切换不同的功能模块。
-
实现的结构大致如下:
- 那么现在的问题就是如何将在
CompanySelect.vue
中设置的公司名称,传给Header.vue
来展示。 - 按前端模块化的思路,每个模块(
.vue
或.jsx
)都有自己独立的state
与props
来处理数据与界面渲染的绑定。 - 在这个功能场景下,可以通过
App.vue
在创建Header.vue
和CompanySelect.vue
模块的时候,设定回调函数,在CompanySelect.vue
输入公司名称后,由回调函数把值最终传给Header.vue
来显示:
Flux化
- 按
Flux
的思路来重构:
- 一个项目(或者大模块)将会确定一个根。
- 在这个根上拥有
state
和改变state
的事件方法。- 根之下的功能模块“舍弃”自己的
state
,数据的来源与变化改为根的state。- 功能模块中的操作事件只会触发根上的事件方法,不实现具体的业务逻辑。

- 在这个例子中,
CompanySelect.vue
本身将不会保存公司名称的变量,“确定”按钮只把输入的值通过事件传给根(App.vue
),由根进行保存和传递给其他组件。
- 失去
state
和业务逻辑的功能模块,将会弱化成单纯的显示组件,所有的数据供给和业务逻辑由根来组装提供。 - 这种改变,有利于复杂项目的前端模块化,实现显示组件的复用化。
网友评论