安装:
npm install reflux
引入:
var Reflux = require("reflux");//CommonJS风格 commonjs导出的话 需要使用 module.exports=导出定义的名字
import Reflux from "reflux";//ES6风格
Reflux的主要功能是引入一个函数式编程风格架构,采用单向数据流模式,而非MVC类似的模式。
这个模式由actions和data stores组成。当actions引入新数据时,要经过data stores之后再由view 组件展示。如果组件有事件要更改data stores,也需要经过相应的actions再传递到stores。
要用reflux,我们需要创建可以被React Component唤起的actions;负责存储、更新数据的stores,stores会监听actions;同样的,stores会与React Component挂钩 ,当store里state更新时,也更新React Component中的state。因此,有3个概念如下:
1、创建actions
2、创建stores
3、创建 stores与React Component的联系(钩子)
一个Reflux应用只包含3个部分: Action,负责消息的分发,一般是由用户行为触发 Store,负责监听Action的触发,也负责通知View更新UI View,负责监听Store的数据变化,在Store数据变化之后,会自上而下完成一次渲染(re-render)

此时会有人问:没有了消息中枢(Dispatcher),消息Actions如何发布出去,并传递到Stores呢?
答:在Reflux中,每一个Action本身就是一个Publisher(消息发布者),即自带了消息发布功能;而每一个Store除了作为数据存储之外,它还是一个Subscriber,或者叫做Listener(消息订阅者),自然就可以通过监听Action,来获取到变化的数据。
一般说来,在实际项目代码中,由于涉及到的Action较多,所以一般都是调用Reflux.createActions()一次性创建Actions集合,比较方便。另外,之后Store通过listenables字段与Action进行关联时,需要的也是一个Actions集合。
Reflux单向数据流的实现,是完全基于PubSub设计模式的。 Action,Store和View三者的角色分配以及分工合作,如下: Action 是一个Publisher,负责消息的分发,一般是由用户行为(User Interaction),或是Web API触发。
Store 不仅是一个Publisher,还是一个Subscriber(或者叫做Listener),作为Subscriber,负责监听Action的触发;作为Publisher,则负责通知View更新UI。
View 是一个Subscriber,负责监听Store的数据变化,做到及时更新UI。 在Reflux中,因为没有了Action Creator的概念,所以,Action的创建都是通过统一的API:Reflux.createAction()或者Reflux.createActions()来实现。
答:Reflux抽取出两个模块:PublisherMethods 和 ListenerMethods,顾名思义,这两个集合分别存储着一个对象作为Publisher和Listener所应该具有的方法。
比如:
PublisherMethods(时间抛发)中包括:trigger、triggerAsync等消息发布方法。
ListenerMethods(事件更新和侦听)中就包括listenTo、listenToMany等消息订阅方法。
// 拥有配置
var action = Reflux.createAction({
actionName: 'addItem', // 其实这个actionName并没有什么用,可不传
asyncResult: true,
sync: false,
children: ['success']
});
// 简化
var action = Reflux.createAction('addItem')
// 或者匿名
var addItemAction = Reflux.createAction();
sync: 设置为true,指定action的默认触发方式为 同步 children: 用于创建子Action(主要是用在异步操作的时候,后面会讲到) asyncResult:设置为true时,自动创建两个名为'completed'和'failed'的子Action(可以认为是设置子Action的一个快捷方式)
2.通过Reflux.createActions()创建多个Action,即Actions集合,代码如下
var actions = Reflux.createActions(['addItem', 'deleteItem']);
// 个别action配置
var actions = Reflux.createActions(['addItem', {
deleteItem: {
asyncResult: true,
children: ['success'],
},
updateItem: {...}
}]);
// 也可以这样
var actions = Reflux.createActions({
addItem: {},
deleteItem: {
asyncResult: true,
children: ['success']
},
updateItem: {...}
注意:Reflux.createActions()返回的是一个普通的对象,即Actions集合,所以Action触发时,需要指定actionName,就像这样:
actions.addItem({...});
actions.deleteItem();
一般说来,在实际项目代码中,由于涉及到的Action较多,所以一般都是调用Reflux.createActions()一次性创建Actions集合,比较方便。另外,之后Store通过listenables字段与Action进行关联时,需要的也是一个Actions集合。
之前就提到,Action作为一个Publisher,会拥有PublisherMethods集合里提供的一系列方法,这里统一举例说明 listen:Action消息订阅
var addAction = Reflux.createAction();
addAction.listen(function (url) {
// 默认上下文this是addAction
$.ajax(url).done(function () {
// todo: save to store
});
});
addAction('/xxx/add');
rigger 同步触发Action消息,在触发具体的消息之前,首先会先执行preEmit和shouldEmit回调。
preEmit返回值(非undefined)将作为shouldEmit函数的入参,用于修改payload shouldEmit的返回值(true or false),将作为是否真正触发消息的标志
preEmit用于异步请求,下面两种方法是等价的
var actions = Reflux.createActions({
add: {
asyncResult: true,
preEmit: function (url) {
$.ajax(url)
.done(this.completed)
.fail(this.failed);
}
}
});
// 等价于
var actions = Reflux.createActions({
add: {
asyncResult: true
}
});
actions.add.listen(function(url) {
$.ajax(url)
.done(this.completed)
.fail(this.failed)
});
preEmit用于修改payload
var actions = Reflux.createActions(['takePhoto']);
// 映射
var maps = {
'photo': {
maxSize: 1000 // 从相册获取
},
'camera': { // 拍照
maxSize: 2000,
maxSelect: 10
}
};
actions.takePhoto.preEmit = function (type) {
return maps[type] || maps['photo'];
};
actions.takePhoto.listen(function (options) {
// do ajax
console.log(options);
});
actions.takePhoto('photo');
// 或者
shouldEmit的使用(防止action的频繁触发)
var requesting = false;
var actions = Reflux.createActions(['submit']);
actions.submit.shouldEmit = function () {
return !requesting;
}
actions.submit.listen(function (url) {
requesting = true;
$.ajax(url).done(function () {
// success
}).fail(function () {
// error
}).always(function () {
requesting = false;
});
});
// 点击按钮
$('#btn').click(function () {
actions.submit('url/submit');
});
romise: 语法糖,用于简写异步Action,下面两种方法是等价的:
var addAction = Reflux.createAction({
children: ['completed', 'failed'] // 等价于 asyncResult: true
});
addAction.listen(function (url) {
var me = this;
$.ajax(url).done(function (data) {
me.completed(data);
}).fail(function () {
me.failed();
});
});
// 等价于
addAction.listen(function (url) {
this.promise($.ajax(url));
});
addAction('/url/add');
listenAndPromise: 是上述两个方法listen和promise方法的结合,做了两件事情:消息订阅和异步回调。 比如上面的例子,就可以这样简写
addAction.listenAndPromise(function(url) {
return $.ajax(url); // 注意:返回promise对象
});
riggerAsync: 异步触发Action消息(而trigger同步触发消息),类似于
setTimeout(function () {action();}, 0)
triggerPromise 触发Action消息,可以通过返回的promise将异步请求的数据直接带回,而不需要经过Store。
var addAction = Reflux.createAction({
asyncResult: true
});
addAction.listenAndPromise(function(url) {
return $.ajax(url); // 注意:返回promise对象
});
// 触发消息,监听异步子action的成功与失败
// action这里可以获取到数据,
addAction.triggerPromise('/url/add').then(function (data) {
console.log(data);
}, function () {
console.log('failed');
});