资讯专栏INFORMATION COLUMN

React Reflux

ormsf / 357人阅读

摘要:概念是根据的创建的单向数据流类库。的单向数据流模式主要由和组成。数据更新成功后,还是通过事件机制传递的组件当中,并更新。整个过程的对接是通过事件驱动的。标识如果首字母大写就会识别不了,例如将上面的改成。

概念

Reflux是根据React的flux创建的单向数据流类库。
Reflux的单向数据流模式主要由actions和stores组成。例如,当组件list新增item时,会调用actions的某个方法(如addItem(data)),并将新的数据当参数传递进去,通过事件机制,数据会传递到stroes中,stores可以向服务器发起请求,并更新数据数据库。数据更新成功后,还是通过事件机制传递的组件list当中,并更新ui。整个过程的对接是通过事件驱动的。就像这样:

</>复制代码

  1. ╔═════════╗ ╔════════╗ ╔═════════════════╗
  2. ║ Actions ║──────>║ Stores ║──────>║ View Components ║
  3. ╚═════════╝ ╚════════╝ ╚═════════════════╝
  4. ^ │
  5. └──────────────────────────────────────┘

代码看起来像这样的:

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "addItem"
  3. ]);
  4. var TodoStore = Reflux.createStore({
  5. items: [1, 2],
  6. listenables: [TodoActions],
  7. onAddItem: function (model) {
  8. $.post("/server/add", {data: model}, function (data) {
  9. this.items.unshift(data);
  10. this.trigger(this.items);
  11. });
  12. }
  13. });
  14. var TodoComponent = React.createClass({
  15. mixins: [Reflux.listenTo(TodoStore, "onStatusChange")],
  16. getInitialState: function () {
  17. return {list: []};
  18. },
  19. onStatusChange: function () {
  20. this.setState({list: TodoStore.items});
  21. },
  22. render: function () {
  23. return (
  24. {this.state.list.map(function (item) {
  25. return

    {item}

  26. })}
  27. )
  28. }
  29. });
  30. React.render(, document.getElementById("container"));
同React Flux比较 相同点

有actions

有stores

单向数据流

不同点

通过内部拓展actions的行为,移除了单例的dispatcher

stores可以监听actions的行为,无需进行冗杂的switch判断

stores可以相互监听,可以进行进一步的数据聚合操作,类似于,map/reduce

waitFor被连续和平行的数据流所替代

创建Action

</>复制代码

  1. var statusUpdate = Reflux.createAction(options);

返回值是一个函数,调用这个函数就会触发相应的事件,在store中监听这个函数,并作相应的处理

</>复制代码

  1. var addItem = Reflux.createAction();
  2. var TodoStore = Reflux.createStore({
  3. init: function () {
  4. this.listenTo(addItem, "addItem");
  5. },
  6. addItem: function (model) {
  7. console.log(model);
  8. }
  9. });
  10. addItem({name: "xxx"});
创建多个Action

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "addItem",
  3. "deleteItem"
  4. ]);

store监听actions的行为:

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "addItem",
  3. "deleteItem"
  4. ]);
  5. var TodoStore = Reflux.createStore({
  6. init: function () {
  7. this.listenTo(TodoActions.addItem, "addItem");
  8. this.listenTo(TodoActions.deleteItem, "deleteItem");
  9. },
  10. addItem: function (model) {
  11. console.log(model)
  12. },
  13. deleteItem:function(model){
  14. console.log(model);
  15. }
  16. });
  17. TodoActions.addItem({name:"xxx"});
  18. TodoActions.deleteItem({name:"yyy"});
异步Action

真实的应用场景中,几乎所有的操作都会向后端请求,而这些操作都是异步的,Reflux也提供了相应的Promise接口

</>复制代码

  1. var getAll = Reflux.createAction({asyncResult:true});

例如获取全部数据:

</>复制代码

  1. var getAll = Reflux.createAction({asyncResult: true});
  2. var TodoStore = Reflux.createStore({
  3. init: function () {
  4. this.listenTo(getAll, "getAll");
  5. },
  6. getAll: function (model) {
  7. $.get("/all", function (data) {
  8. if (data) {
  9. getAll.completed(data);
  10. } else {
  11. getAll.failed(data);
  12. }
  13. });
  14. }
  15. });
  16. getAll({name: "xxx"})
  17. .then(function (data) {
  18. console.log(data);
  19. })
  20. .catch(function (err) {
  21. throw err;
  22. });
Action hooks

Reflux为每个action都提供了两个hook方法

preEmit(params),action emit之前调用,参数是action传递过来的,返回值会传递给shouldEmit

shouldEmit(params) action emit之前调用,参数默认是action传递,如果preEmit有返回值,则是preEmit返回值,返回值决定是否emit

情景一:

</>复制代码

  1. var addItem = Reflux.createAction({
  2. preEmit: function (params) {
  3. console.log("preEmit:" + params);
  4. },
  5. shouldEmit: function (params) {
  6. console.log("shouldEmit:" + params);
  7. }
  8. });
  9. var TodoStore = Reflux.createStore({
  10. init: function () {
  11. this.listenTo(addItem, "addItem");
  12. },
  13. addItem: function (params) {
  14. console.log("addItem:" + params);
  15. }
  16. });
  17. addItem("xxx");
  18. 控制台打印
  19. $ preEmit:xxx
  20. $ shouldEmit:xxx

情景二:

</>复制代码

  1. var addItem = Reflux.createAction({
  2. preEmit: function (params) {
  3. console.log("preEmit:" + params);
  4. return 324;
  5. },
  6. shouldEmit: function (params) {
  7. console.log("shouldEmit:" + params);
  8. return true;
  9. }
  10. });
  11. var TodoStore = Reflux.createStore({
  12. init: function () {
  13. this.listenTo(addItem, "addItem");
  14. },
  15. addItem: function (params) {
  16. console.log("addItem:" + params);
  17. }
  18. });
  19. addItem("xxx");
  20. 控制台打印
  21. $ preEmit:xxx
  22. $ shouldEmit:324
  23. $ addItem:324

</>复制代码

  1. 注意几个返回值和参数的关系

Action Methods

当需要给所有的action添加公用方法时,可以这么干:

</>复制代码

  1. Reflux.ActionMethods.print = function (str) {
  2. console.log(str);
  3. };
  4. var addItem = Reflux.createAction();
  5. var TodoStore = Reflux.createStore({
  6. init: function () {
  7. this.listenTo(addItem, "addItem");
  8. },
  9. addItem: function (params) {
  10. console.log("addItem:" + params);
  11. }
  12. });
  13. addItem.print("xxx");
trigger、triggerAsync和triggerPromise

直接调用addItem()实际上是调用trigger或者triggerAsync或者triggerPromise,它们区别在于

</>复制代码

  1. var addItem = Reflux.createAction(); addItem(); #默认调用triggerAsync,相当于addItem.triggerAsync()
  2. var addItem = Reflux.createAction({sync:true});addItem(); #默认调用trigger,相当于addItem.trigger()
  3. var addItem = Reflux.createAction({asyncResult:true});addItem();#默认调用triggerPromise,相当于addItem.triggerPromise()

trigger和triggerAsync区别在于:

</>复制代码

  1. triggerAsync = setTimeout(function () {
  2. trigger()
  3. }, 0);

trigger和triggerPromise区别在于,triggerPromise的返回值是promise

创建Store

Store可以响应Action的行为,并同服务器交互。

监听单个Action

在init方法中添加监听处理

</>复制代码

  1. var addItem = Reflux.createAction();
  2. var TodoStore = Reflux.createStore({
  3. init: function () {
  4. this.listenTo(addItem, "addItem");
  5. },
  6. addItem: function (model) {
  7. console.log(model);
  8. }
  9. });
  10. addItem({name: "xxx"});
监听多个Action 作死写法

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "addItem",
  3. "deleteItem"
  4. ]);
  5. var TodoStore = Reflux.createStore({
  6. init: function () {
  7. this.listenTo(TodoActions.addItem, "addItem");
  8. this.listenTo(TodoActions.deleteItem, "deleteItem");
  9. },
  10. addItem: function (model) {
  11. console.log(model);
  12. },
  13. deleteItem: function (model) {
  14. console.log(model);
  15. }
  16. });
  17. TodoActions.addItem({name: "xxx"});
  18. TodoActions.deleteItem({name: "yyy"});

两个action的时候在init里写了两遍监听处理方法,如果有十个甚至多个的话,写起来就像这样的:

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "item1",
  3. "item2",
  4. "item3",
  5. "item4",
  6. "item5",
  7. "item6",
  8. "item7",
  9. "item8",
  10. "item9",
  11. "item10"
  12. ]);
  13. var TodoStore = Reflux.createStore({
  14. init: function () {
  15. this.listenTo(TodoActions.item1, "item1");
  16. this.listenTo(TodoActions.item2, "item2");
  17. this.listenTo(TodoActions.item3, "item3");
  18. this.listenTo(TodoActions.item4, "item4");
  19. this.listenTo(TodoActions.item5, "item5");
  20. this.listenTo(TodoActions.item6, "item6");
  21. this.listenTo(TodoActions.item7, "item7");
  22. this.listenTo(TodoActions.item8, "item8");
  23. this.listenTo(TodoActions.item9, "item9");
  24. this.listenTo(TodoActions.item10, "item10");
  25. },
  26. item1: function (model) {
  27. console.log(model);
  28. },
  29. item2: function (model) {
  30. console.log(model);
  31. }
  32. });
  33. TodoActions.item1({name: "xxx"});
  34. TodoActions.item2({name: "yyy"});
listenToMany

还好Reflux给我们提供了listenToMany方法,避免重复劳动:

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "item1",
  3. "item2",
  4. "item3",
  5. "item4",
  6. "item5",
  7. "item6",
  8. "item7",
  9. "item8",
  10. "item9",
  11. "item10"
  12. ]);
  13. var TodoStore = Reflux.createStore({
  14. init: function () {
  15. this.listenToMany(TodoActions);
  16. },
  17. onItem1: function (model) {
  18. console.log(model);
  19. },
  20. onItem2: function (model) {
  21. console.log(model);
  22. }
  23. });
  24. TodoActions.item1({name: "xxx"});
  25. TodoActions.item2({name: "yyy"});

处理方法只需让action的标识首字母大写并加上on就可以了。

</>复制代码

  1. 标识如果首字母大写就会识别不了,例如将上面的item1改成Itme1。这坑爹的!

listenables

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "item1",
  3. "item2",
  4. "item3",
  5. "item4",
  6. "item5",
  7. "item6",
  8. "item7",
  9. "item8",
  10. "item9",
  11. "item10"
  12. ]);
  13. var TodoStore = Reflux.createStore({
  14. listenables: [TodoActions],
  15. onItem1: function (model) {
  16. console.log(model);
  17. },
  18. onItem2: function (model) {
  19. console.log(model);
  20. }
  21. });
  22. TodoActions.item1({name: "xxx"});
  23. TodoActions.item2({name: "yyy"});

一般我们写真实应用的时候都应该采用这种写法!!!

Store Methods

拓展Store的公用方法有两种方式。

方式一

</>复制代码

  1. Reflux.StoreMethods.print = function (str) {
  2. console.log(str);
  3. };
  4. var addItem = Reflux.createAction();
  5. var TodoStore = Reflux.createStore({
  6. init: function () {
  7. this.listenTo(addItem, "addItem");
  8. },
  9. addItem: function (model) {
  10. console.log(model);
  11. }
  12. });
  13. TodoStore.print("rrr");
方式二

</>复制代码

  1. var Mixins = {
  2. print: function (str) {
  3. console.log(str);
  4. }
  5. }
  6. var addItem = Reflux.createAction();
  7. var TodoStore = Reflux.createStore({
  8. mixins: [Mixins],
  9. init: function () {
  10. this.listenTo(addItem, "addItem");
  11. },
  12. addItem: function (model) {
  13. console.log(model);
  14. }
  15. });
  16. TodoStore.print("rrr");
同组件结合

前面说了,Action、Store和组件这三者是通过事件机制响应变化的,构建组件的时候首先需要监听Store的状态。
先定义Action和Store

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "getAll"
  3. ]);
  4. var TodoStore = Reflux.createStore({
  5. items: [1,2,3],
  6. listenables: [TodoActions],
  7. onGetAll: function () {
  8. this.trigger(this.items);
  9. }
  10. });
基本

</>复制代码

  1. var TodoComponent = React.createClass({
  2. getInitialState: function () {
  3. return {list: []};
  4. },
  5. onStatusChange: function (list) {
  6. this.setState({list: list});
  7. },
  8. componentDidMount: function () {
  9. this.unsubscribe = TodoStore.listen(this.onStatusChange);
  10. TodoActions.getAll();
  11. },
  12. componentWillUnmount: function () {
  13. this.unsubscribe();
  14. },
  15. render: function () {
  16. return (
  17. {this.state.list.map(function (item) {
  18. return

    {item}

  19. })}
  20. )
  21. }
  22. });
  23. React.render(, document.getElementById("container"));

这里有两点需要注意:

当组件的生命周期结束时需要解除对Store的监听

当Store调用trigger时,才会执行onStatusChange函数,所以每次Store更新时,需要手动调用trigger函数

Mixins

</>复制代码

  1. var TodoComponent = React.createClass({
  2. mixins: [Reflux.ListenerMixin],
  3. getInitialState: function () {
  4. return {list: []};
  5. },
  6. onStatusChange: function (list) {
  7. this.setState({list: list});
  8. },
  9. componentDidMount: function () {
  10. this.unsubscribe = TodoStore.listen(this.onStatusChange);
  11. TodoActions.getAll();
  12. },
  13. render: function () {
  14. return (
  15. {this.state.list.map(function (item) {
  16. return

    {item}

  17. })}
  18. )
  19. }
  20. });
  21. React.render(, document.getElementById("container"));
Reflux.listenTo

</>复制代码

  1. var TodoComponent = React.createClass({
  2. mixins: [Reflux.listenTo(TodoStore,"onStatusChange")],
  3. getInitialState: function () {
  4. return {list: []};
  5. },
  6. onStatusChange: function (list) {
  7. this.setState({list: list});
  8. },
  9. componentDidMount: function () {
  10. TodoActions.getAll();
  11. },
  12. render: function () {
  13. return (
  14. {this.state.list.map(function (item) {
  15. return

    {item}

  16. })}
  17. )
  18. }
  19. });
  20. React.render(, document.getElementById("container"));
Reflux.connect

</>复制代码

  1. var TodoComponent = React.createClass({
  2. mixins: [Reflux.connect(TodoStore,"list")],
  3. getInitialState: function () {
  4. return {list: []};
  5. },
  6. componentDidMount: function () {
  7. TodoActions.getAll();
  8. },
  9. render: function () {
  10. return (
  11. {this.state.list.map(function (item) {
  12. return

    {item}

  13. })}
  14. )
  15. }
  16. });
  17. React.render(, document.getElementById("container"));

数据会自动更新到state的list当中。

Reflux.connectFilter

</>复制代码

  1. var TodoComponent = React.createClass({
  2. mixins: [Reflux.connectFilter(TodoStore, "list", function (list) {
  3. return list.filter(function (item) {
  4. return item > 1;
  5. });
  6. })],
  7. getInitialState: function () {
  8. return {list: []};
  9. },
  10. componentDidMount: function () {
  11. TodoActions.getAll();
  12. },
  13. render: function () {
  14. return (
  15. {this.state.list.map(function (item) {
  16. return

    {item}

  17. })}
  18. )
  19. }
  20. });
  21. React.render(, document.getElementById("container"));

对数据加了一层过滤器。

</>复制代码

  1. 以上便Component同Store交互的内容,大家可以根据实际情况选择不同的写法。

小结

我这人喜欢拿代码来表述思想。

</>复制代码

  1. var TodoActions = Reflux.createActions([
  2. "getAll",
  3. "addItem",
  4. "deleteItem",
  5. "updateItem"
  6. ]);
  7. var TodoStore = Reflux.createStore({
  8. items: [1, 2, 3],
  9. listenables: [TodoActions],
  10. onGetAll: function () {
  11. $.get("/all", function (data) {
  12. this.items = data;
  13. this.trigger(this.items);
  14. }.bind(this));
  15. },
  16. onAddItem: function (model) {
  17. $.post("/add", model, function (data) {
  18. this.items.unshift(data);
  19. this.trigger(this.items);
  20. }.bind(this));
  21. },
  22. onDeleteItem: function (model, index) {
  23. $.post("/delete", model, function (data) {
  24. this.items.splice(index, 1);
  25. this.trigger(this.items);
  26. }.bind(this));
  27. },
  28. onUpdateItem: function (model, index) {
  29. $.post("/update", model, function (data) {
  30. this.items[index] = data;
  31. this.trigger(this.items);
  32. }.bind(this));
  33. }
  34. });
  35. var TodoComponent = React.createClass({
  36. mixins: [Reflux.connect(TodoStore, "list")],
  37. getInitialState: function () {
  38. return {list: []};
  39. },
  40. componentDidMount: function () {
  41. TodoActions.getAll();
  42. },
  43. render: function () {
  44. return (
  45. {this.state.list.map(function(item){
  46. return
  47. })}
  48. )
  49. }
  50. });
  51. var TodoItem = React.createClass({
  52. componentDidMount: function () {
  53. TodoActions.getAll();
  54. },
  55. handleAdd: function (model) {
  56. TodoActions.addItem(model);
  57. },
  58. handleDelete: function (model,index) {
  59. TodoActions.deleteItem(model,index);
  60. },
  61. handleUpdate: function (model) {
  62. TodoActions.updateItem(model);
  63. },
  64. render: function () {
  65. var item=this.props.data;
  66. return (
  67. {item.name}

  68. {item.email}

  69. /*操作按钮*/

  70. )
  71. }
  72. });
  73. React.render(, document.getElementById("container"));

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

代码链接

github

参考

Reflux

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92330.html

相关文章

  • React 可视化开发工具 Shadow Widget 非正经入门(之四:flux、mvc、mvvm

    摘要:是分发器,是数据与逻辑处理器,会在注册针对各个命令字的响应回调函数。当按如下方式触发回调时,回调函数具备事件的特性。 本系列博文从 Shadow Widget 作者的视角,解释该框架的设计要点。本篇解释 Shadow Widget 在 MVC、MVVM、Flux 框架之间如何做选择。 showImg(https://segmentfault.com/img/bVOODj?w=380&h...

    msup 评论0 收藏0
  • React使用总结

    摘要:当使用对象时,在生命周期中运行,此时环境下已经完成了。并不会随着的更新而改变,因此在使用时一定要注意是否有。但是使用会跳过的过程,会触发子组件的所有方法包括从而造成性能的浪费。因此为了组件更加清晰高效,应该避免使用。我推荐使用来管理。 两种架构 现在使用React的开发模式主要有两种——freeMarker+React以及纯静态React页面开发。本文着重介绍纯静态React页面的开...

    LoftySoul 评论0 收藏0
  • React 可视化开发工具 shadow-widget 最佳实践(上)

    摘要:上例的功能块定义了如下节点树入口节点是面板,结合该节点的函数书写特点,我们接着介绍最佳实践如何处理功能块之内的编程。 本文介绍 React + Shadow Widget 应用于通用 GUI 开发的最佳实践,只聚焦于典型场景下最优开发方法。分上、下两篇讲解,上篇概述最佳实践,介绍功能块划分。 showImg(https://segmentfault.com/img/bVWu3d?w=6...

    techstay 评论0 收藏0
  • React为什么需要Flux-like的库

    摘要:的关键构成梳理了一下,需要配合的库去使用,是因为要解决通信问题。还有各个事件之间,有可能存在依赖关系,事件后,也触发。相比于传统的事件系统,融入了不少的思想。中,将会是最大的门槛之一。 从学习React到现在的一点感受 我觉得应该有不少同学和我一样,上来学React,觉得甚是惊艳,看着看着,发现facebook 安利了一个flux,图画的巨复杂,然后各种例子都有用这个东西,没办法,硬着...

    wangtdgoodluck 评论0 收藏0

发表评论

0条评论

ormsf

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<