谈谈Flux
原文链接 https://syaning.github.io/2016/03/21/flux/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
参考资料
1. 什么是Flux
首先,Flux是一种应用架构,是一种模式,而不是一个框架。它有着多种实现。例如Facebook官方实现,Redux等。
2. 为什么要使用Flux
Flux的出现主要是为了解决应用的状态维护问题。在小型项目中,Model和View可能是一一对应的关系,维护起来并不困难。但是随着应用规模的扩大,Model和View通常是多对多的关系,每一个Model的改变,和它相关的View都要改变;每个View的操作,也都要反映到它相关的Model上。在这种情况下,状态的维护会变得复杂和混乱。
3. Flux的基本结构
Flux的基本结构如图:
简化结构如下:
图片来源:https://facebook.github.io/flux/docs/overview.html#content
首先,可以看到Flux的一个特点是单向数据流。
Flux的基本组成包括:
- View
- Action
- Dispatcher
- Store
它们的功能和关系是:
- View负责展示给用户
- 用户与View的交互会发出Action,例如click操作
- Dispatcher收到Action后进行派发给相应的Store
- Store更新数据,发出change事件
- View接收到change事件,更新界面
4. 如何使用
下面通过一个非常简单的例子来介绍Flux的基本使用。
(1) Dispatcher
Dispatcher的创建非常简单:
var Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();
(2) Action
Action就是一个普通的对象,在Action中通过dispatcher.dispatch(payload)
来分发事件。每个payload
有一个type
(或类似的名称)属性来表示Action的类型,此外可以有其它的属性来传递该Action所相关的数据。
const dispatcher = require('./dispatcher')
var actions = {
addItem: function(text) {
dispatcher.dispatch({
type: 'add',
text
})
}
}
module.exports = actions
(3) Store
Store用来存放数据模型。通过事件系统(这里使用的是Node的EventEmitter,也可以使用其它的实现)可以发出和接收事件。
通过dispatcher.register(callback)
来注册回调函数,从而当Dispatcher接收到Action的时候,会通知Store来更新数据。
当Store更新后,要发出change事件。
const EventEmitter = require('events').EventEmitter
const dispatcher = require('./dispatcher')
var items = []
var store = Object.create(EventEmitter.prototype, {
items: {
get: function() {
return items
}
}
})
function addItem(text) {
items.push(text)
}
dispatcher.register(function(action) {
switch (action.type) {
case 'add':
addItem(action.text)
store.emit('change')
break
default:
break
}
})
module.exports = store
(4) View
View就是React的组件了。用户的交互会通过Action发出事件。
const React = require('react')
const store = require('./store')
const action = require('./action')
class App extends React.Component {
constructor(props) {
// ...
}
componentDidMount() {
store.on('change', this.onItemsChange.bind(this))
}
componentWillUnmount() {
store.removeListener('change', this.onItemsChange.bind(this))
}
onItemsChange() {
// ...
}
// ...
addItem() {
action.addItem(this.state.value)
// ...
}
render() {
// ...
}
}
module.exports = App
5. 注意点
- 只有一个全局的Dispatcher
- Action用来描述做什么事,通过
dispatcher.dispatch(payload)
来分发事件,不涉及具体的数据逻辑 - Store不是Model,Store内存放着Model
- 如果应用规模较大,可以根据应用模块来分成多个Store
- 只有Store才可以通过
dispatcher.register(callback)
来注册回调函数