在React的世界,初学的时候总是会遇到一些新奇的名词:Flux,Redux等。因为React并不是一个完整的前端框架,它只是一个可以创建虚拟DOM的View层。所以要想实现完整的前端框架,它就需要一些朋友帮忙,一个典型的框架就是Backbone。不过Flux和Redux这样的朋友是Facebook自己推出的,这篇文章主要介绍一下Flux这个朋友。这个在线聊天室就是根据Flux的思想架构起来的。理解了它,你就会发现
js
文件夹下的文件结构很清晰了。
什么是Flux
引用Flux官网的说法:
Flux is the application architecture that Facebook uses for building client-side web applications. It complements React’s composable view components by utilizing a unidirectional data flow. It’s more of a pattern rather than a formal framework, and you can start using Flux immediately without a lot of new code.
意译过来就是:
Flux是Facebook出品的,用来构建前端结构的工具。它利用单项数据流实现和React组件的无缝对接。说它是工具,但其实它只是一种模式,没必要对它产生恐惧,因为它基本没有什么新的代码。
解读
当然了,光听Facebook这么安抚,我们是不会立即消退对新事物对恐惧感的,上一张图可能更容易理解它:
从上图可以看出,Flux就是一个组件-动作-调度-存储-组件
的单向数据循环:
- 一个组件只负责监听和启动动作(Actions),并从存储(Stores)中读取数据并更新。
- 无论什么动作,都发送给调度员(Dispatcher)。
- 调度员(Dispatcher)统一调配,发给需要的存储(Stores)。
- 存储(Stores)只负责接收调度员发过来的匹配的信息,更新数据,发给它管辖的组件。
通过这种方法,Flux给了我们这样一个调度员,我们就不用再劳神在组件中管理数据的存取了,只需要把数据发送给调度员即可。
回顾文件结构
这时候,再来看在线聊天室的js
文件夹,你会发现:
- 调度员(Dospatcher)在
js
文件夹的根目录,方便所有组件、动作和存储调用; - 组件、动作和存储分别被放入对应的文件夹,保持结构的整洁;
- 每一个组件对应的动作和存储,都会以相同文件名关联起来,方便我们调试、搜索和维护(如
Rooms.js
组件对应的动作文件是RoomsActions.js
,对应的存储文件是RoomsStore.js
)。
安装与配置Flux
有了Flux提供的调度员这个好帮手,我们要做的就是:
- 用npm安装它:
npm i -S flux
- 在js根目录创建一个
dispatcher.js
文件,复制粘贴如下代码并保存:
import { Dispatcher } from 'flux';
export default new Dispatcher;
实例
现在我们已经了解了Flux,并成功安装了它,但是它究竟是如何运行的呢?我还是把Rooms
的组件、动作与存储拿出来做个说明:
首先我们已经有了Rooms.js
组件:https://github.com/shisaq/chat-server/blob/master/static/js/components/Rooms.js
注意看它的constructor
,在20行关于State的代码:
constructor() {
super();
this.state = {
rooms: RoomsStore.getAll()
};
}
我们在这里把Rooms
组件的数据托管到了RoomsStore.js
中。在RoomsStore
内部:
constructor() {
super();
this.rooms = [];
}
getAll() {
return this.rooms;
}
这样就实现了通过在RoomsStore
中添加所需的function管理数据,进而更新到Rooms
组件中。
这里有几点要注意:
-
Rooms
组件既然要使用RoomsStore
,就不要忘记在头部引入:import RoomsStore from '../stores/RoomsStore';
-
RoomsStore
既然要被调度员管理,就要引入调度员:import dispatcher from '../dispatcher';
-
RoomsStore
发送和监听数据是靠EventEmitter
实现的,所以记得先引入EventEmitter
:import { EventEmitter } from 'events';
关于EventEmitter
EventEmitter是Node.js下的东西,我们已经安装了npm,所以Node.js也早就有了。不需要安装额外的东西。它的主要作用就是:
从RoomsStore
的一个方法发送一个自定义名称的事件,在Rooms
配置一个同名称的监听事件。通过这种方法,Rooms
组件就能动态且顺利地接收到RoomsStore
的数据了。这个方法其实和SocketIO很像。栗子:
RoomsStore
发送一个名为addNewRoom
的事件,并把数据发送给Rooms
:
this.emit('addNewRoom', data);
Rooms
在componentWillMount()
(React状态管理,渲染前要执行的代码)中添加监听事件:
RoomsStore.on('addNewRoom', (data) => {
this.setState({
rooms: RoomsStore.getAll()
});
this.props.socket.emit('join_private_room', data);
大专栏