概念

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'));

实际情况远比这复杂,只是提供一个思路供大家参考。

延伸阅读


▶ Walkthrough007

React Reflux相关推荐

  1. React+Reflux博客实践

    年初用React+Express+Mongodb写的一个简单的博客.分享给各位朋友参考. 前端:React+React Router+Reflux+React-Bootstrap+Webpack 后端 ...

  2. java webpack web项目_spring + spring mvc + mybatis + react + reflux + webpack Web工程例子

    前言 最近写了个Java Web工程demo,使用maven构建: 后端使用spring + spring mvc + mybatis: 前端使用react + react-router+ webpa ...

  3. React+Redux系列教程

    2019独角兽企业重金招聘Python工程师标准>>> 参考项目:https://github.com/lewis617/react-redux-tutorial 参考项目下载地址: ...

  4. 彻底征服 React.js + Flux + Redux【讲师辅导】-曾亮-专题视频课程

    彻底征服 React.js + Flux + Redux[讲师辅导]-74574人已学习 课程介绍         [会员免费]链接 http://edu.csdn.net/lecturer/585 ...

  5. Modbus 通讯协议 (RTU传输模式)

    注:( 2020.05.22 ) GB/T 19582.2-2008 <基于Modbus协议的工业自动化网络规范 第1部分:Modbus协议在串行链路上的实现指南> 1.对于modbus ...

  6. IMWebConf 2016总结

    IMWebConf 2016总结 9月10号,IMWeb团队在腾讯大厦成功举办了IMWebConf 2016!进行了一次十分精彩的分享沙龙! 一.一句话总结 [影响力范围] 听众来自腾讯.爱奇艺.OP ...

  7. 使用reflux进行react组件之间的通信

    前言 组件之间为什么要通信?因为有依赖. 那么,作为React组件,怎么通信? React官网说, 进行 父-子 通信,可以直接pass props. 进行 子-父 通信,往父组件传给子组件的函数注入 ...

  8. react 和 reflux

    目录 一.介绍: 二.特征: 三.组成: 四.react 的基本概念: 五.JSX语法: 六.生命周期: 七.简单的使用: 一.介绍: react:最早来源于FaceBook,后来因为其独特的设计思想 ...

  9. React.js开发生态系统概览 [译-转]

    React.js 开发生态系统概览 [译] JavaScript领域发展速度很快,甚至有人认为这已经引起了负效应.一个前端库从早期开发的小玩具,到流行,再到过时,可能也就几个月时间.判断一个工具能否在 ...

最新文章

  1. 【机器学习】RNN循环神经网络
  2. 怎样实现前端裁剪上传图片功能
  3. python 三引号_Python 字符串
  4. 3DSlicer相关资料汇总
  5. SpringBoot基础篇配置信息之配置刷新
  6. javase基础第三天
  7. Java错误提示框口怎么使用_如何在Swing中显示错误消息对话框?
  8. 将日期变为中文星期几
  9. E9流程表单中动态自定义添加button js代码
  10. python入门--字典的特点
  11. linux 离线安装node.js,Linux上离线安装node.js、Newman、newman-reporter-html
  12. ERP原理 : 第五节 销售管理的工作原理
  13. division by zero_MySQL5.7 group_by报错问题解决办法,大部分程序员都收藏了
  14. Secure Multiparty Computation (MPC)
  15. Android技术点滴记录
  16. 【Hive】if函数用法
  17. 在Mac上运行.exe文件
  18. 参考文献格式生成器(GB/T 7714-2015)
  19. 计数问题:1~n中x出现了多少次?
  20. 计算方法(五)函数插值

热门文章

  1. 改进duilib的richedit控件的部分功能
  2. 清华计算机系本科毕业起薪,大学本科毕业起薪最高的六大专业
  3. 运维-Linux简介
  4. LZY碎大石(YYOJ)(优先队列
  5. Spark入门-什么是Spark
  6. 百度百科怎么引流?如何进行百度百科推广?百度百科推广怎么做?
  7. Win系统蓝牙设备删除失败 - 解决方案
  8. MySQL不同隔离级别并发测试分析
  9. html布局优先级,iOS Masonry 设置布局优先级。
  10. oracle any 语法,Oracle:apos;= ANY()apos;与apos;IN()apos; Dovov编程网