Reflux 使用教程
Reflux是根据React的flux创建的单向数据流类库。
Reflux的单向数据流模式主要由actions和stores组成。例如,当组件list新增item时,会调用actions的某个方法(如addItem(data)),并将新的数据当参数传递进去,通过事件机制,数据会传递到stroes中,stores可以向服务器发起请求,并更新数据数据库。数据更新成功后,还是通过事件机制传递的组件list当中,并更新ui。整个过程的对接是通过事件驱动的。就像这样:
╔═════════╗ ╔════════╗ ╔═════════════════╗
║ Actions ║──────>║ Stores ║──────>║ View Components ║
╚═════════╝ ╚════════╝ ╚═════════════════╝
^ │
└──────────────────────────────────────┘
代码看起来像这样的:
var TodoActions = Reflux.createActions([
'addItem'
]);
var TodoStore = Reflux.createStore({
items: [1, 2],
listenables: [TodoActions],
onAddItem: function (model) {
$.post('/server/add', {data: model}, function (data) {
this.items.unshift(data);
this.trigger(this.items);
});
}
});
var TodoComponent = React.createClass({
mixins: [Reflux.listenTo(TodoStore, 'onStatusChange')],
getInitialState: function () {
return {list: []};
},
onStatusChange: function () {
this.setState({list: TodoStore.items});
},
render: function () {
return (
<div>
{this.state.list.map(function (item) {
return <p>{item}</p>
})}
</div>
)
}
});
React.render(<TodoComponent />, document.getElementById('container'));
同React Flux比较
相同点
- 有actions
- 有stores
- 单向数据流
不同点
- 通过内部拓展actions的行为,移除了单例的dispatcher
- stores可以监听actions的行为,无需进行冗杂的switch判断
- stores可以相互监听,可以进行进一步的数据聚合操作,类似于,map/reduce
- waitFor被连续和平行的数据流所替代
创建Action
var statusUpdate = Reflux.createAction(options);
返回值是一个函数,调用这个函数就会触发相应的事件,在store中监听这个函数,并作相应的处理
var addItem = Reflux.createAction();
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(addItem, 'addItem');
},
addItem: function (model) {
console.log(model);
}
});
addItem({name: 'xxx'});
创建多个Action
var TodoActions = Reflux.createActions([
'addItem',
'deleteItem'
]);
store监听actions的行为:
var TodoActions = Reflux.createActions([
'addItem',
'deleteItem'
]);
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(TodoActions.addItem, 'addItem');
this.listenTo(TodoActions.deleteItem, 'deleteItem');
},
addItem: function (model) {
console.log(model)
},
deleteItem:function(model){
console.log(model);
}
});
TodoActions.addItem({name:'xxx'});
TodoActions.deleteItem({name:'yyy'});
异步Action
真实的应用场景中,几乎所有的操作都会向后端请求,而这些操作都是异步的,Reflux也提供了相应的Promise接口
var getAll = Reflux.createAction({asyncResult:true});
例如获取全部数据:
var getAll = Reflux.createAction({asyncResult: true});
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(getAll, 'getAll');
},
getAll: function (model) {
$.get('/all', function (data) {
if (data) {
getAll.completed(data);
} else {
getAll.failed(data);
}
});
}
});
getAll({name: 'xxx'})
.then(function (data) {
console.log(data);
})
.catch(function (err) {
throw err;
});
Action hooks
Reflux为每个action都提供了两个hook方法
- preEmit(params),action emit之前调用,参数是action传递过来的,返回值会传递给shouldEmit
- shouldEmit(params) action emit之前调用,参数默认是action传递,如果preEmit有返回值,则是preEmit返回值,返回值决定是否emit
情景一:
var addItem = Reflux.createAction({
preEmit: function (params) {
console.log('preEmit:' + params);
},
shouldEmit: function (params) {
console.log('shouldEmit:' + params);
}
});
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(addItem, 'addItem');
},
addItem: function (params) {
console.log('addItem:' + params);
}
});
addItem('xxx');
控制台打印
$ preEmit:xxx
$ shouldEmit:xxx
情景二:
var addItem = Reflux.createAction({
preEmit: function (params) {
console.log('preEmit:' + params);
return 324;
},
shouldEmit: function (params) {
console.log('shouldEmit:' + params);
return true;
}
});
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(addItem, 'addItem');
},
addItem: function (params) {
console.log('addItem:' + params);
}
});
addItem('xxx');
控制台打印
$ preEmit:xxx
$ shouldEmit:324
$ addItem:324
注意几个返回值和参数的关系
Action Methods
当需要给所有的action添加公用方法时,可以这么干:
Reflux.ActionMethods.print = function (str) {
console.log(str);
};
var addItem = Reflux.createAction();
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(addItem, 'addItem');
},
addItem: function (params) {
console.log('addItem:' + params);
}
});
addItem.print('xxx');
trigger、triggerAsync和triggerPromise
直接调用addItem()实际上是调用trigger或者triggerAsync或者triggerPromise,它们区别在于
var addItem = Reflux.createAction(); addItem(); #默认调用triggerAsync,相当于addItem.triggerAsync()
var addItem = Reflux.createAction({sync:true});addItem(); #默认调用trigger,相当于addItem.trigger()
var addItem = Reflux.createAction({asyncResult:true});addItem();#默认调用triggerPromise,相当于addItem.triggerPromise()
trigger和triggerAsync区别在于:
triggerAsync = setTimeout(function () {
trigger()
}, 0);
trigger和triggerPromise区别在于,triggerPromise的返回值是promise
创建Store
Store可以响应Action的行为,并同服务器交互。
监听单个Action
在init方法中添加监听处理
var addItem = Reflux.createAction();
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(addItem, 'addItem');
},
addItem: function (model) {
console.log(model);
}
});
addItem({name: 'xxx'});
监听多个Action
作死写法
var TodoActions = Reflux.createActions([
'addItem',
'deleteItem'
]);
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(TodoActions.addItem, 'addItem');
this.listenTo(TodoActions.deleteItem, 'deleteItem');
},
addItem: function (model) {
console.log(model);
},
deleteItem: function (model) {
console.log(model);
}
});
TodoActions.addItem({name: 'xxx'});
TodoActions.deleteItem({name: 'yyy'});
两个action的时候在init里写了两遍监听处理方法,如果有十个甚至多个的话,写起来就像这样的:
var TodoActions = Reflux.createActions([
'item1',
'item2',
'item3',
'item4',
'item5',
'item6',
'item7',
'item8',
'item9',
'item10'
]);
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(TodoActions.item1, 'item1');
this.listenTo(TodoActions.item2, 'item2');
this.listenTo(TodoActions.item3, 'item3');
this.listenTo(TodoActions.item4, 'item4');
this.listenTo(TodoActions.item5, 'item5');
this.listenTo(TodoActions.item6, 'item6');
this.listenTo(TodoActions.item7, 'item7');
this.listenTo(TodoActions.item8, 'item8');
this.listenTo(TodoActions.item9, 'item9');
this.listenTo(TodoActions.item10, 'item10');
},
item1: function (model) {
console.log(model);
},
item2: function (model) {
console.log(model);
}
});
TodoActions.item1({name: 'xxx'});
TodoActions.item2({name: 'yyy'});
listenToMany
还好Reflux给我们提供了listenToMany方法,避免重复劳动:
var TodoActions = Reflux.createActions([
'item1',
'item2',
'item3',
'item4',
'item5',
'item6',
'item7',
'item8',
'item9',
'item10'
]);
var TodoStore = Reflux.createStore({
init: function () {
this.listenToMany(TodoActions);
},
onItem1: function (model) {
console.log(model);
},
onItem2: function (model) {
console.log(model);
}
});
TodoActions.item1({name: 'xxx'});
TodoActions.item2({name: 'yyy'});
处理方法只需让action的标识首字母大写并加上on就可以了。
标识如果首字母大写就会识别不了,例如将上面的item1改成Itme1。这坑爹的!
listenables
var TodoActions = Reflux.createActions([
'item1',
'item2',
'item3',
'item4',
'item5',
'item6',
'item7',
'item8',
'item9',
'item10'
]);
var TodoStore = Reflux.createStore({
listenables: [TodoActions],
onItem1: function (model) {
console.log(model);
},
onItem2: function (model) {
console.log(model);
}
});
TodoActions.item1({name: 'xxx'});
TodoActions.item2({name: 'yyy'});
一般我们写真实应用的时候都应该采用这种写法!!!
Store Methods
拓展Store的公用方法有两种方式。
方式一
Reflux.StoreMethods.print = function (str) {
console.log(str);
};
var addItem = Reflux.createAction();
var TodoStore = Reflux.createStore({
init: function () {
this.listenTo(addItem, 'addItem');
},
addItem: function (model) {
console.log(model);
}
});
TodoStore.print('rrr');
方式二
var Mixins = {
print: function (str) {
console.log(str);
}
}
var addItem = Reflux.createAction();
var TodoStore = Reflux.createStore({
mixins: [Mixins],
init: function () {
this.listenTo(addItem, 'addItem');
},
addItem: function (model) {
console.log(model);
}
});
TodoStore.print('rrr');
同组件结合
前面说了,Action、Store和组件这三者是通过事件机制响应变化的,构建组件的时候首先需要监听Store的状态。
先定义Action和Store
var TodoActions = Reflux.createActions([
'getAll'
]);
var TodoStore = Reflux.createStore({
items: [1,2,3],
listenables: [TodoActions],
onGetAll: function () {
this.trigger(this.items);
}
});
基本
var TodoComponent = React.createClass({
getInitialState: function () {
return {list: []};
},
onStatusChange: function (list) {
this.setState({list: list});
},
componentDidMount: function () {
this.unsubscribe = TodoStore.listen(this.onStatusChange);
TodoActions.getAll();
},
componentWillUnmount: function () {
this.unsubscribe();
},
render: function () {
return (
<div>
{this.state.list.map(function (item) {
return <p>{item}</p>
})}
</div>
)
}
});
React.render(<TodoComponent />, document.getElementById('container'));
这里有两点需要注意:
- 当组件的生命周期结束时需要解除对Store的监听
- 当Store调用trigger时,才会执行onStatusChange函数,所以每次Store更新时,需要手动调用trigger函数
Mixins
var TodoComponent = React.createClass({
mixins: [Reflux.ListenerMixin],
getInitialState: function () {
return {list: []};
},
onStatusChange: function (list) {
this.setState({list: list});
},
componentDidMount: function () {
this.unsubscribe = TodoStore.listen(this.onStatusChange);
TodoActions.getAll();
},
render: function () {
return (
<div>
{this.state.list.map(function (item) {
return <p>{item}</p>
})}
</div>
)
}
});
React.render(<TodoComponent />, document.getElementById('container'));
Reflux.listenTo
var TodoComponent = React.createClass({
mixins: [Reflux.listenTo(TodoStore,'onStatusChange')],
getInitialState: function () {
return {list: []};
},
onStatusChange: function (list) {
this.setState({list: list});
},
componentDidMount: function () {
TodoActions.getAll();
},
render: function () {
return (
<div>
{this.state.list.map(function (item) {
return <p>{item}</p>
})}
</div>
)
}
});
React.render(<TodoComponent />, document.getElementById('container'));
Reflux.connect
var TodoComponent = React.createClass({
mixins: [Reflux.connect(TodoStore,'list')],
getInitialState: function () {
return {list: []};
},
componentDidMount: function () {
TodoActions.getAll();
},
render: function () {
return (
<div>
{this.state.list.map(function (item) {
return <p>{item}</p>
})}
</div>
)
}
});
React.render(<TodoComponent />, document.getElementById('container'));
数据会自动更新到state的list当中。
Reflux.connectFilter
var TodoComponent = React.createClass({
mixins: [Reflux.connectFilter(TodoStore, 'list', function (list) {
return list.filter(function (item) {
return item > 1;
});
})],
getInitialState: function () {
return {list: []};
},
componentDidMount: function () {
TodoActions.getAll();
},
render: function () {
return (
<div>
{this.state.list.map(function (item) {
return <p>{item}</p>
})}
</div>
)
}
});
React.render(<TodoComponent />, document.getElementById('container'));
对数据加了一层过滤器。
以上便Component同Store交互的内容,大家可以根据实际情况选择不同的写法。
小结
我这人喜欢拿代码来表述思想。
var TodoActions = Reflux.createActions([
'getAll',
'addItem',
'deleteItem',
'updateItem'
]);
var TodoStore = Reflux.createStore({
items: [1, 2, 3],
listenables: [TodoActions],
onGetAll: function () {
$.get('/all', function (data) {
this.items = data;
this.trigger(this.items);
}.bind(this));
},
onAddItem: function (model) {
$.post('/add', model, function (data) {
this.items.unshift(data);
this.trigger(this.items);
}.bind(this));
},
onDeleteItem: function (model, index) {
$.post('/delete', model, function (data) {
this.items.splice(index, 1);
this.trigger(this.items);
}.bind(this));
},
onUpdateItem: function (model, index) {
$.post('/update', model, function (data) {
this.items[index] = data;
this.trigger(this.items);
}.bind(this));
}
});
var TodoComponent = React.createClass({
mixins: [Reflux.connect(TodoStore, 'list')],
getInitialState: function () {
return {list: []};
},
componentDidMount: function () {
TodoActions.getAll();
},
render: function () {
return (
<div>
{this.state.list.map(function(item){
return <TodoItem data={item}/>
})}
</div>
)
}
});
var TodoItem = React.createClass({
componentDidMount: function () {
TodoActions.getAll();
},
handleAdd: function (model) {
TodoActions.addItem(model);
},
handleDelete: function (model,index) {
TodoActions.deleteItem(model,index);
},
handleUpdate: function (model) {
TodoActions.updateItem(model);
},
render: function () {
var item=this.props.data;
return (
<div>
<p>{item.name}</p>
<p>{item.email}</p>
<p>/*操作按钮*/</p>
</div>
)
}
});
React.render(<TodoComponent />, document.getElementById('container'));
实际情况远比这复杂,只是提供一个思路供大家参考。
Reflux 使用教程的更多相关文章
- react+reflux入门教程
为了简化react的flux带来的冗余操作,社区的同仁们给我们带来了很多优秀的轮子,诸如redux,reflux等.今天我们就通过逐行讲解代码实例的方法,感受一番reflux的设计之美. 例子 这个例 ...
- Reflux中文教程——概览
翻译自github上的reflux项目,链接:https://github.com/reflux/refluxjs 〇.安装及引入 安装: npm install reflux 引入: var Ref ...
- Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求
上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...
- Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数
上一篇:Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数 之前介绍了简单的路由以及传参,这篇文章我们将要学习复杂一些的路由以及传递其他附加参数.一个好的路由系统可以使我们 ...
- Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数
上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...
- Angular2入门系列教程4-服务
上一篇文章 Angular2入门系列教程-多个组件,主从关系 在编程中,我们通常会将数据提供单独分离出来,以免在编写程序的过程中反复复制粘贴数据请求的代码 Angular2中提供了依赖注入的概念,使得 ...
- Angular2入门系列教程1-使用Angular-cli搭建Angular2开发环境
一直在学Angular2,百忙之中抽点时间来写个简单的教程. 2016年是前端飞速发展的一年,前端越来越形成了(web component)组件化的编程模式:以前Jquery通吃一切的田园时代一去不复 ...
- wepack+sass+vue 入门教程(三)
十一.安装sass文件转换为css需要的相关依赖包 npm install --save-dev sass-loader style-loader css-loader loader的作用是辅助web ...
- wepack+sass+vue 入门教程(二)
六.新建webpack配置文件 webpack.config.js 文件整体框架内容如下,后续会详细说明每个配置项的配置 webpack.config.js直接放在项目demo目录下 module.e ...
随机推荐
- Android恢复出厂设置流程分析【Android源码解析十】
最近看恢复出厂的一个问题,以前也查过这方面的流程,所以这里整理一些AP+framework层的流程: 在setting-->备份与重置--->恢复出厂设置--->重置手机---> ...
- TCP/IP远程访问操作:rwho,rlogin,rcp和rsh
TCP/IP网络通信 软件 包使用远程访问 的 命令 ,这些命令首先是由UC Berkely为Arpanet开发的.它允许您远程注册到另一个 系统 中,并从一个系统复制文件到另一个系统.您能取得关于一 ...
- 使用Reporting Service订阅对域外用户发邮件
默认情况下使用Reporting Service对域外邮件发送会失败,一般可能会碰到下面的两个错误: ERROR 1: Subscription Error: "The e-mail add ...
- iOS8 Core Image In Swift:人脸检测以及马赛克
iOS8 Core Image In Swift:自动改善图像以及内置滤镜的使用 iOS8 Core Image In Swift:更复杂的滤镜 iOS8 Core Image In Swift:人脸 ...
- last与lastlog命令
lastlog 列出所有用户最后登录的时间和登录终端的地址,如果此用户从来没有登录,则显示:**Never logged in**last 列出用户所有的登录时间和登录终端的地址
- StackOverflow程序员推荐:每个程序员都应读的30本书
“如果能时光倒流,回到过去,作为一个开发人员,你可以告诉自己在职业生涯初期应该读一本,你会选择哪本书呢?我希望这个书单列表内容丰富,可以涵盖很多东西.” 很多程序员响应,他们在推荐时也写下自己的评语. ...
- C#管理IIS中的站点
原文:http://www.knowsky.com/534237.html Microsoft自Windows Vista一起发布了IIS 7.0,这个已经是去年的话题了,随后,由.NET开发的Web ...
- varchar和Nvarchar的区别
(1)varchar(N) 存储时 N的单位是字节 比如说varchar(2) 代表的是 该字段可以存储字节长度为2的数据 例子:可以添加 张 或者 ab 添加成功! 但添加的时候如果是: ...
- (原)使用intel的ipp库计算卷积及相关
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5462631.html 参考网址: https://software.intel.com/zh-cn/n ...
- redis学习研究--Redis作者谈Redis应用场景
毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作,为不同的大象 ...