摘要:概念是根据的创建的单向数据流类库。的单向数据流模式主要由和组成。数据更新成功后,还是通过事件机制传递的组件当中,并更新。整个过程的对接是通过事件驱动的。标识如果首字母大写就会识别不了,例如将上面的改成。
概念
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 (同React Flux比较 相同点{this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
有actions
有stores
单向数据流
不同点通过内部拓展actions的行为,移除了单例的dispatcher
stores可以监听actions的行为,无需进行冗杂的switch判断
stores可以相互监听,可以进行进一步的数据聚合操作,类似于,map/reduce
waitFor被连续和平行的数据流所替代
创建Actionvar 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
创建StoreStore可以响应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就可以了。
listenables标识如果首字母大写就会识别不了,例如将上面的item1改成Itme1。这坑爹的!
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 ({this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
这里有两点需要注意:
当组件的生命周期结束时需要解除对Store的监听
当Store调用trigger时,才会执行onStatusChange函数,所以每次Store更新时,需要手动调用trigger函数
Mixinsvar 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 (Reflux.listenTo{this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
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 (Reflux.connect{this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
var TodoComponent = React.createClass({ mixins: [Reflux.connect(TodoStore,"list")], getInitialState: function () { return {list: []}; }, componentDidMount: function () { TodoActions.getAll(); }, render: function () { return ({this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
数据会自动更新到state的list当中。
Reflux.connectFiltervar 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 ({this.state.list.map(function (item) { return) } }); React.render({item}
})}, 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 ({this.state.list.map(function(item){ return) } }); 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 (})} ) } }); React.render({item.name}
{item.email}
/*操作按钮*/
, document.getElementById("container"));
实际情况远比这复杂,只是提供一个思路供大家参考。
代码链接github
参考Reflux
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/92330.html
摘要:是分发器,是数据与逻辑处理器,会在注册针对各个命令字的响应回调函数。当按如下方式触发回调时,回调函数具备事件的特性。 本系列博文从 Shadow Widget 作者的视角,解释该框架的设计要点。本篇解释 Shadow Widget 在 MVC、MVVM、Flux 框架之间如何做选择。 showImg(https://segmentfault.com/img/bVOODj?w=380&h...
摘要:上例的功能块定义了如下节点树入口节点是面板,结合该节点的函数书写特点,我们接着介绍最佳实践如何处理功能块之内的编程。 本文介绍 React + Shadow Widget 应用于通用 GUI 开发的最佳实践,只聚焦于典型场景下最优开发方法。分上、下两篇讲解,上篇概述最佳实践,介绍功能块划分。 showImg(https://segmentfault.com/img/bVWu3d?w=6...
摘要:的关键构成梳理了一下,需要配合的库去使用,是因为要解决通信问题。还有各个事件之间,有可能存在依赖关系,事件后,也触发。相比于传统的事件系统,融入了不少的思想。中,将会是最大的门槛之一。 从学习React到现在的一点感受 我觉得应该有不少同学和我一样,上来学React,觉得甚是惊艳,看着看着,发现facebook 安利了一个flux,图画的巨复杂,然后各种例子都有用这个东西,没办法,硬着...
阅读 1075·2021-11-25 09:43
阅读 1542·2021-10-25 09:47
阅读 2449·2019-08-30 13:46
阅读 739·2019-08-29 13:45
阅读 1266·2019-08-26 13:29
阅读 2963·2019-08-23 15:30
阅读 1085·2019-08-23 14:17
阅读 1311·2019-08-23 13:43