react开发中,组件直接传递参数需要props一层层代理,对于复杂组件,它可能嵌套的子组件非常多,层级也比较深,那么,如果还采用props链条来维护组件通信或者数据共享,将非常困难,也不利于开发和维护。因此,衍生出了Flux、Redux和react-redux,本篇主要介绍Flux。
Flux框架也是一种MVC框架,它采用单向数据流,不允许Model和Control互相引用。Flux框架大致如下:
Views:视图界面,如react组件等渲染标签的文件
Action:驱动Dispatcher,只要Store中有注册Dispatcher监听,就可以获取到Action想要执行的动作数据。
Dispatcher:负责分发,关联Action(接收方)与Store(处理方)
Store:状态变化的逻辑处理、状态存储
Flux Demo演示代码:https://github.com/smallH/react-flux-demo.git
通过该Demo大家可以了解到Flux的运行机制,那么直接看代码吧,先看看组件树的顶层 :
// FluxDemo.jsx
import React from 'react';
import FluxView from './FluxView.jsx';
import FluxStore from './FluxStore.js';
class FluxDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
data: FluxStore.getData()
};
this.onChange = this.onChange.bind(this);
}
componentDidMount() {
FluxStore.addChangeListener(this.onChange);
}
componentWillUnmount() {
FluxStore.removeChangeListener(this.onChange);
}
onChange() {
const newData = FluxStore.getData();
this.setState({
data: newData
});
}
render() {
return(
<div>
<FluxView data={this.state.data}/>
</div>
);
}
}
export default FluxDemo;
从这段代码很明显可以看出,组件树的顶层除了渲染子组件FluxView外什么事情都不干,所有控制权都交给了store,而且并没有任何处理子组件的逻辑业务(逻辑都放在了store中处理)。它有两个重要步骤:(1)挂载完成和卸载时,要添加/移除store中监听;(2)传递到子组件的状态必须从store中获得。简单来说,就是store告诉我改变什么数据来源,我就做什么。
再看看被渲染的子组件FluxView,该组件主要模拟了通过点击事件触发Action操作:
// FluxView.jsx
import React from 'react';
import FluxAcion from './FluxAcion';
class FluxView extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.newHandle = this.newHandle.bind(this);
this.updateHandle = this.updateHandle.bind(this);
}
newHandle() {
FluxAcion.newData("[new action]");
}
updateHandle() {
FluxAcion.updateData("[update action]");
}
render() {
return(
<div>
current data is ======= {this.props.data}
<div>
<button onClick={this.newHandle}>execute action [New] </button>
<button onClick={this.updateHandle}>execute action [Update] </button>
<button>...</button>
</div>
</div>
);
}
}
export default FluxView;
这一步,我告诉了Action我触发了什么事件,如newData还是updaDate,这就够了,其他的事情交给Action去干就好,现在我们看看Action是如何联系Dispatcher模块去影响Store的:
// FluxDispatcher.js
import { Dispatcher } from 'flux';
const FluxDispatcher = new Dispatcher();
export default FluxDispatcher;
// FluxConstants.js
const FluxContants = {
NEW: 'NEW',
UPDATE: 'UPDATE'
};
export default FluxContants;
// FluxAcion.js
import FluxConstants from './FluxConstants';
import FluxDispatcher from './FluxDispatcher';
const FluxAcion = {
newData(data) {
// Dispatcher 触发
FluxDispatcher.dispatch({
type: FluxConstants.NEW,
value: data
});
},
updateData(data) {
// Dispatcher 触发
FluxDispatcher.dispatch({
type: FluxConstants.UPDATE,
value: data
});
}
}
export default FluxAcion;
Action也不做任何逻辑处理,只负责驱动了Dispatcher,通过.dispatch()分发任务,这时若store有注册了Dispatcher监听,就可以拿到Dispatch分发过来的任务,这样整个闭环功能就完整连接起来了。最后,看看Flux最核心的store:
// FluxStore.js
import { EventEmitter } from 'events';
import FluxDispatcher from './FluxDispatcher';
import FluxConstants from './FluxConstants';
let data = "[default]";
// store 构造
const store = Object.assign({}, EventEmitter.prototype, {
getData: function() {
return data;
},
emitChange: function() {
this.emit('change');
},
addChangeListener: function(callback) {
this.on('change', callback);
},
removeChangeListener: function(callback) {
this.removeListener('change', callback);
}
});
// Dispatcher 注册
FluxDispatcher.register((action) => {
switch(action.type) {
case FluxConstants.NEW:
data = action.value + "+ 数据操作所需的逻辑处理...";
store.emitChange();
break;
case FluxConstants.UPDATE:
data = action.value + "+ 数据操作所需的逻辑处理...";
store.emitChange();
break;
default:
break
}
});
export default store;
store实现了从Dispatcher处得到数据来源和类型,然后对数据的进行逻辑处理,并向外提供了一个getData()的接口,让组件可以获取变化后的状态数据,这一整套下来的模式就是Flux。
通过点击按钮去驱动[New] Action 和 [update] Action 实现当前data状态的变化。
Flux有三个缺点:
1. 一个应用可以拥有多个store、action,多个store直接可能有依赖关系。
2. Store封装了数据和处理数据的逻辑,state已经被暴露出来谁都可以改变。
3. 使用Flux的组件复用性差,具有Flux元素耦合,不符合react设计思想。
因而,Redux出现了,并通过很巧妙的方式解决了这些缺点。