说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

详解React Flux架构工作方式

HTML文档下载 WORD文档下载 PDF文档下载
Flux是Facebook内部用来构建React应用的一套架构,该架构的最大特点是其倡导的单向数据流方案。本文将重点讨论Facebook Flux架构的工作方式,以及开发者应该如何在项目中使用它。

【编者按】作者Ken Wheeler在《 Getting To Know Flux, the React.js Architecture》一文中 讨论Facebook的Flux架构的工作方式,以及开发者应该如何在项目中使用它。为了让前端开发者更好地掌握本文内容,景庄对该文章进行了翻译,内容如下:

什么是Flux

Flux是Facebook内部用来构建React应用的一套架构。它本身并不是一个框架或库。它仅仅是一个用于完善React应用开发的一种新的应用程序架构,Flux架构最大的特点是其倡导的单向数据流方案。

Facebook还提供了Dispatcher的开源库。你可以将Dispatcher认为是一种全局pub/sub系统的事件处理器,用于向所注册的回调函数广播payloads。通常情况下,如果你使用Flux架构,你可以借助于Facebook提供的这个Dispatcher实现,并且可以借助NodeJS中的EventEmitter模块来配置事件系统, 从而帮助管理应用程序的状态。

组成结构

Flux主要包括下面四个独立的组件,下面简单地解释下:

  • Actions:帮助向Dispatcher传递数据的辅助方法;
  • Dispatcher:接收action,并且向注册的回调函数广播payloads;
  • Stores:应用程序状态的容器&并且含有注册到Dispatcher的回调函数;
  • Controller Views:React组件,从Store获取状态,并将其逐级向下传递给子组件。

让我们通过一幅图来简单看一下这四个部分的关系:


如何处理外部API

但是,很多场景下不仅仅包括应用程序内部的状态数据,还可能包括来自外部的数据,也就是如果我们需要消费RESTful服务,那么我们该如何将这些外部数据引入到Flux架构的单向数据流中呢?经过实践,我们发现,在Action中引入外部数据流是个不错的实践, 数据然后再被送到Store中。

在继续阅读之前,我强烈建议你阅读下Facebook提供的Flux官方示例程序的 源代码。在你简单阅读了这个例子的源代码后,我们再来详细的探讨Flux中这几个组件的作用:

Dispatcher

我们首先来看看Dispatcher的作用:你可以将Dispatcher看成是Flux架构中整个数据流程的管理者。或者你可以将它看成你整个应用的中央交换机。Dispatcher接收actions作为payloads,并且将payloads分发给所注册的回调函数。

那么它就是一个pub/sub吗?

不完全是。Dispatcher会将payload广播给所有向它注册的回调函数,并且包括了允许你以指定次序调用这些回掉函数的执行逻辑,例如在处理前等待数据更新。在Flux架构中只有一个Dispatcher,它是你整个应用的中央Hub。我们来创建一个简单的Dispatcher:

var Dispatcher = require('flux').Dispatcher;var AppDispatcher = new Dispatcher();AppDispatcher.handleViewAction = function(action) {  this.dispatch({    source: 'VIEW_ACTION',    action: action  });}module.exports = AppDispatcher;

在上面的代码中,我们创建了一个Dispatcher的实例,它包括了一个叫做handleViewAction的方法。创建这个方法的目的是为了让你能够轻松的区分, 是视图层触发的action,还是服务器/API触发的action。

在handleViewAction方法中调用了dispatch方法(该方法来自Dispatcher实现),它会将payloads广播给所有注册到它的回调函数 (注意,这里所说的回调是在store中注册给Dispatcher的)。然后,action会触发Store中相应事件,并最终体现在state的更新上。

可以用下面这张图来表示这个过程:


依赖

Facebook所提供的Dispatcher模块还有一个非常赞的功能,那就是它能够定义依赖,并在Store中向Dispatcher注册回调函数。 因此,如果你的应用的某个部分依赖于其他部分的数据更新,为了能够进行合适的渲染,Dispatcher中的waitFor方法将会非常有用。

为了能够利用这一特性,我们需要在Store中存储注册给Dispatcher的回调函数的返回值,这里,我们命名为dispatcherIndex:

ShoeStore.dispatcherIndex = AppDispatcher.register(function(payload) {});

然后在Store中处理每一个被分发的action时,我们可以使用Dispatcher的waitFor方法来确保我们的ShoeStore已经被更新了,示例代码如下:

case 'BUY_SHOES':  AppDispatcher.waitFor([    ShoeStore.dispatcherIndex  ], function() {    CheckoutStore.purchaseShoes(ShoeStore.getSelectedShoes());  });  break;

Stores

在Flux中,可以用Store来分领域的管理应用程序的状态,例如ShoeStore、AppStore等。从一个更高层角度来看,可以简单地认为应用的每一个部分可以对应于一个Store,Store可以用来管理数据,定义数据检索方法,此外,Store中还包括了注册给Dispatcher的回调函数。

下面我们来看一个简单的Store的例子:

var AppDispatcher = require('../dispatcher/AppDispatcher');var ShoeConstants = require('../constants/ShoeConstants');var EventEmitter = require('events').EventEmitter;var merge = require('react/lib/merge');// Internal object of shoesvar _shoes = {};// Method to load shoes from action datafunction loadShoes(data) {  _shoes = data.shoes;}// Merge our store with Node's Event Emittervar ShoeStore = merge(EventEmitter.prototype, {  // Returns all shoes  getShoes: function() {    return _shoes;  },  emitChange: function() {    this.emit('change');  },  addChangeListener: function(callback) {    this.on('change', callback);  },  removeChangeListener: function(callback) {    this.removeListener('change', callback);  }});// Register dispatcher callbackAppDispatcher.register(function(payload) {  var action = payload.action;  var text;  // Define what to do for certain actions  switch(action.actionType) {    case ShoeConstants.LOAD_SHOES:      // Call internal method based upon dispatched action      loadShoes(action.data);      break;    default:      return true;  }    // If action was acted upon, emit change event  ShoeStore.emitChange();  return true;});module.exports = ShoeStore;

以上代码可能做的最重要的一件事就是:我们使用NodeJS中的EventEmitter模块来扩展我们的Store。这使得我们的Store能够监听和广播事件。这也使得我们的视图/组件能够基于这些事件来更新。 这是因为我们的控制器视图(Controller View)会监听我们的Store, 并利用这一点通过发出事件方式通知控制器视图应用程序的状态发生了改变, 从而进行视图层的重新渲染。

在Store中还有一个值得注意的事,那就是我们使用Dispatcher的regiter方法来注册回调函数。 这意味着,我们创建的Store会监听来自AppDispatcher的广播,这里我们使用switch语句来 区分广播内容所对应的action。如果一个相关的action发生了,那么就触发一个change事件,并且监听 此事件的视图会根据新的状态(state)进行重新渲染。这个过程如下图所示。


在上面的代码中,ShoeStore中还包括一个公共方法getShoes(),它可以在控制器视图中被调用, 用于检索所有在_shoes对象中的数据,并且使用这个数据作为组件的状态数据。因为这是个非常简单 的例子,在实际应用开发中你可以使用更加复杂的数据处理逻辑。

Action创建器和Actions

行为创建器(Action Creators)是一组会在视图中被调用的方法(也可以在其他地方使用), 它们用于向Dispatcher发送actions。也就是说,我们使用Dispatcher分发的payloads,实际上就是actions。

在Facebook提供的例子中,action的类型常数被用于定义这些action所被应用的场景,并且是伴随着action一起被传递的。现在,在所注册的回调函数内部,这些actions可以根据他们的action类型来处理。

我们可以看一个简单的类型常数的定义:

var keyMirror = require('react/lib/keyMirror');module.exports = keyMirror({  LOAD_SHOES: null});

在上面的代码中,我们用了React的keyMirror库来生成我们的类型常数的Key/Value对。如果仅仅是看这个文件,我们大致可以猜到我们的应用会加载鞋子(shoes)。借助于类型常数,可以使得应用 中涉及到的事物变得更加地可组织,可以让开发者能通过这样的高层抽象来组织应用程序。

现在,让我们来大致的看一个对应的行为创建器(action creator)的定义:

var AppDispatcher = require('../dispatcher/AppDispatcher');var ShoeStoreConstants = require('../constants/ShoeStoreConstants');var ShoeStoreActions = {  loadShoes: function(data) {    AppDispatcher.handleAction({      actionType: ShoeStoreConstants.LOAD_SHOES,      data: data    })  }};module.exports = ShoeStoreActions;

在上面的代码中,我们在定义了ShoeStoreActions对象,并在其中定义了loadShoes()方法, 该方法内调用了来自AppDispatcher的handleViewAction方法,并且将相应的行为类型与 我们提供的数据相关联。现在,我们可以在我们的视图代码或API中引入这个action文件。我们可以调用ShoeStoreActions.loadShoes(ourData)方法来向Dispatcher发送payload,随后Dispatcher会将它广播出去。ShoeStore则会监听来自Dispatcher的广播,并且触发相应的事件来加载相应的鞋子。

控制器视图 Controller View

你可以简单的将控制器视图理解为React组件,这些组件会监听change事件,如果事件发生了, 就从Stores中获取应用程序新的状态数据。随后,可以将数据通过props逐级向子组件传递。这个过程大致如下图所示:


让我们来看看代码长啥样:

/** @jsx React.DOM */var React = require('react');var ShoesStore = require('../stores/ShoeStore');// Method to retrieve application state from storefunction getAppState() {  return {    shoes: ShoeStore.getShoes()  };}// Create our component classvar ShoeStoreApp = React.createClass({  // Use getAppState method to set initial state  getInitialState: function() {    return getAppState();  },    // Listen for changes  componentDidMount: function() {    ShoeStore.addChangeListener(this._onChange);  },  // Unbind change listener  componentWillUnmount: function() {    ShoesStore.removeChangeListener(this._onChange);  },  render: function() {    return (      <ShoeStore shoes={this.state.shoes} />    );  },    // Update view state when change event is received  _onChange: function() {    this.setState(getAppState());  }});module.exports = ShoeStoreApp;

在上面的代码中,我们使用addChangeListener来监听change事件,并且在接收到事件后更新应用程序的状态数据。

我们的应用程序状态数据存储在Store中,因此我们可以用Store中的公共方法来获取数据,然后将其设置为应用程序的状态。

完整的数据流程

前面我们依次解读了Flux架构中的每一个独立部分,我们有了对Flux架构中的每一个组件的一个大致的认识, 并且能大致的了解了Flux架构的工作流。在这之前,我们已经通过了几张图片描述了数据在组件之间的流向, 现在让我们将上面的子流程组合起来,以更好的理解Flux的数据流:


小结

在读完这篇文章后,如果你之前并不了解Facebook的Flux架构,那么希望你现在能够说理解了。 但另一方面,如果不在React的实际编程开发中使用这一架构,你是很难真正的体会到Flux架构的 特点的。

当你使用Flux后,你会发现没有Flux的React应用开发就相当于是没有jQuery的DOM遍历操作。也就是说, 没有Flux你可以照常进行React应用开发,但是你在代码组织和数据流程上会缺乏优雅的解决方案。

另一个方面,如果你想使用FLux架构,但你并不想使用React,那么你可以参考 Delorean,它是一个Flux框架,并且可以让你使用Ractive.js或者Flight。另一个值得参考的库是 Fluxxor,它实现了在紧耦合的Flux组件中包含一个中央Flux实例。

最后,再次说明,如果要真正的理解Flux,你就得在实际开发中体验它。

原文链接:Getting To Know Flux, the React.js Architecture

译者简介:景庄,前端工程师,关注Node.js、前端工程化。个人博客: http://wwsun.github.com。


欢迎加入CSDN前端交流群2:465281214,进行前端技术交流。  

也可参加CSDN前端大讲堂(微信公开课),享受高含金量在线公开课,与专家讲师在线切磋交流。

如何加入CSDN前端大讲堂?由于该群目前已超过人数限制,所以您首先不得不 扫描下面二维码,加CSDN编辑陈秋歌为好友,然后请她邀请您加入CSDN前端大讲堂微信群。加好友时,请务必注明“申请加入CSDN前端大讲堂”。


Discuz X论坛数据表结构:论坛主题数据表pre_forum_thread Discuz X论坛数据表结构:论坛帖子数据表pre_forum_post jQuery UI 消息框(message box)的使用 kmp算法中的求Next()函数的算法 ASP.NET MVC3 如何将DataTable绑定到Html.DropDownList PHP调用COM组件 农行网上银行支付接口:无法读取商户端配置文件 农行网上银行支付接口:商户代理卖方挂单成交功能测试 Windows Phone 7 实现简单的GPS定位器 C#如何删除string中的Html标记 ImageStone图像处理C++类库 jQuery Mobile 开发入门手册--概述 jQuery Mobile 开发入门手册--技术理论 jQuery Mobile 开发入门手册--组件 SMTP/POP3收发邮件的C#类库SmtPop.Net 用C#编写的Telnet开源类库 Visual Studio C#创建Windows服务(Windows Service) C#取得Windows服务列表 C#编程自动安装Windows服务 C#安装/删除 .NET Windows服务 C#启动、停止、重启Windows服务 jQuery实现Ajax提交form表单的简单方法 字符串String与枚举Enum之间的转换[C#] Javascript统计DOM元素里文字的行数 C#从Web网站下载文件 C#得到区域名称列表 C#合并多个PrintDocument WpWidgetLibrary - Windows Phone的HTML部件库(Widgets) 让你不再害怕C语言指针 C语言概述-C语言教程 Turbo C 2.0集成开发环境的使用(上)-C语言教程 哈哈,需要短信网关IP地址及其源代码的快来顶一下。 sybase12.0安装时的问题??? 怎么样能用asp编写使得IE打开pdf文件?在查询后怎样还能在查询的输入框里面保留查询的输入? 如何使用TreeView进行分级管理 触发器的效率问题! 寻求解决方案 组件刷新问题,UP有分 请问 虚拟目录 和 WEB站点 有什么区别? DBEXPRESS的问题!很简单 请问那里有支持中文好的jsp开发的webmail下载?很急!谢谢大家了! 我如何在程序中切换输入法 怎么把一个COleDateTime类型的变量转成time_t类型(long型)变量? 结构成员这样定义 WCHAR bString[0]; 长度为0有意义吗? 关于DLL中的函数 如何动态分配指针数组? 哪里有关于delphi多线程资料下载? 急!!!SQL2000数据库IMAGE图象数据的存取?????? 这个存储过程怎么写? D7中的这个怎不见了啊-----急急 为什么只能传递两个汉字?有解决的办法吗? 关于DLL文件中的函数 lotus菜鸟请求急就!!!!!!!! 如何动态分配指针数组? 怎样实现点击按钮,将光标所在行的某列参数传到另一个form,显示出另一个表的某条相关记录? 这句话到底有什么含义??? T-SQL连接字符串的操作符号是? 问一个送分问题。 如何得到驱动器信息? (腊肉)欢迎讨论:简体、繁体同界面显示问题 請問在水晶報表里怎樣實現這樣的設計 谁有校友录? 欢迎讨论:简体、繁体同界面显示问题 用VB写了Lable控件,但不知如何把背景是否透明的属性加入 这堆警告是什么意思? 关闭API函数? 怎么按钮的字体的颜色改变不了? 关于图像识别,急急,谢谢 用Oracle8i(个人版)连接Oracle8问题(在线) 用quickreport如何做master/detail 報表 大家请看这段代码(部分):为什么returnValue第一次返回null,第二次返回正确??百分求解 发一个笑话--跟警察牛B的人 呵 请问如何用oledb连sybase11.9.2? 菜鸟问题 请高手指点 为什么服务器端用ontlitcp后informix无法启动呀?? 说能解释一下:阻塞和非阻塞,同步和异步的概念! 很急!拜托!! 欢迎讨论:简体、繁体同界面显示问题 图片上传的问题(100分) 如何直接向clob中插入数据并读出来(高分)? 硬盘使用求救 我是VB菜鸟 问一个很简单的问题 请大家看看 谢谢了 我不太懂他说的是什么意思 你的现在能玩了?我的还是不行啊!麻烦你教教我把! 如何用成语形容明知道是一件错误的事情,但是大家偷偷的都在做,并且成了不是秘密的秘密举例:社保规定社保基数必须如实申报,不能隐瞒,但是大部分企业都是按照最低基数申报,这样操作 什么叫人体细胞膜离子传输酶 电路中电阻特点我用一道题来提问在电路中,R1=20Ω R2=30欧姆 两个电阻并联问总电阻是多少? 什么叫教学型机械臂 除去细胞膜用什么酶?只能用一种酶的情况下 “阳离子、阴离子通过静电作用形成的化学键称作离子键” 这是很多书上的定义.1、为什么要这样定义?2、哪一种化学键不是静电力的体现?3、化学上的定义,为何总是模模糊糊、模棱两可?砖 求问机械手臂过程如何计算? 在电热棒功率要是在400w还可以烧水吗吗 我不知道银河系在哪里谁知道吃饱了银河系怎么办 机械摆臂的设计中间是固定的,是上下往复运动,这种摆臂设计有没有具体地理论参考?望好心人解答. 不能发出紫外线的物体是()A.太阳 B.发光的电灯 C.炉火 D.萤火虫我们老师说是C,可我认为是D,请给我原因,我想知道到底是我错了,还是老师错了 上海航空随机行李尺寸重量我有一个尺寸为484×202×426mm的电脑机箱,能带上飞机么? 怎样使机械臂高速运转 高锰酸钾染色怎么办 帮我计算面积和步骤, HCL,CO2的熔点高低如何,并给下大致原因 细胞膜上有酶么 极地汪洋是什么意思麻烦你务必告诉我i 迎春花是什么颜色啊 金属一般显正价是因为它在反应中一般不得到电子而只失去电子 这句话对吗 它发生硝化反应引入一个硝基时,产物只有一个硝基化合物我想知道.当看到这个条件时.我们能从中得到什么 或者知道什么 计算下列物质的质量:(1)0.2mol硫酸(2)5mol铝 能否用1mol金属反应中失去电子的多少来判断金属性强弱 拉布拉多黄还是黑色多 (1)0.2mol硫酸(H2SO4) 求物质的质量(全过程!) (2)88g二氧化碳 求物质的量(全过程!) 高温物体能否发出紫外线 人生执着什么 为什么蛋白质水解得到氨基酸是取代反应 根据酸碱电子理论,凡是金属原子都可以作为碱吗? 如果没有了执着,人生还有什么意义? 用来判断蛋白质水解程度的反应是:A 茚三酮,B亚硝酸,C异硫氰酸苯脂,D2,4-二硝基氟苯 正相分配色谱适合分离极性大的还是极性小的成分? 执着挣脱命运的枷锁什么意思.? 如果蛋白质水解后双缩脲反应呈阴性时,可以对水解反应程度作出什么样的推论? 氢氧化亚铁为什么先生成白色絮状沉淀在变成绿色絮状沉淀? 数字逻辑实验 用555芯片实现8秒周期震荡电路!急, 谁在电子厂工作过,在电子厂工作好吗 白色氢氧化亚铁为什么先变灰绿,再变红色 非线性混沌实验中倍周期分岔,混沌和奇怪吸引子的物理意义这是我大学物理实验中遇到的一个思考题.希望众位老师能够帮我回答这个问题.我需要它们的物理意义. 能用玻璃做大桥吗 学的是两元一次方程, 解释非线性电路中,什么是混沌? 请问液压机器人手臂与电动机器人手臂相比优缺点,以及现在机器人手臂大多数采用的是那种控制方式, 抛体运动方程及射程怎么求?在高度h,以和水平方向成θ角度的速度v抛出一物体,右手系中的轨迹方程是?射程怎么求? 能沉水,有点香味,有油脂感的老料称杆是什么木料 圆柱坐标型机器人机械手臂是如何确定坐标的 为什么自来水比蒸馏水洗脱能力强一些? 一听天命是什么意思救急啊 金属是不是只可能是电子的转移在感应起电中,正电荷可通过人体转移,但在金属中不是只要电子可以 KMnO4为什么能将NaI氧化 不能将NaCl氧化 氧气为什么能被固体NaOH和浓硫酸干燥?>?>>? 金属在溶液中电子转移的能量基础是什么 为什么气球能把杯子吸住? 已知2mol硫酸分子,求物质的质量急急急急急急~~~ 有哪个成语是形容“明知道这件事不好还要去做的”? 除去细胞膜用啥子酶? 什么意思?具体点说好吗?这些我不太懂.麻烦你了 形容明知道错的还要去做的(成语)至少4个 细胞膜上的酶有什么功能,举例说明 中方严重关切美监听活动报道 要求美方英一座百年恐怖古宅 神秘红衣等了主人澳洲使馆被指替美监听亚洲 北京河内均英议员拒降低果酱含糖量 称或“降格”律师称斯诺登将从11月起在俄大型网站乌克兰加入欧盟协定签署期或推迟到20韩国防部:无计划推动签署韩日军事情报伊拉克向美国请求军事援助 对抗“基地普京获评福布斯2013全球“头号强人英小报窃听引关注 法庭百年后解除部分治污水 防洪水 防内涝 全面打好治水39岁女子当选日本年度美魔女 分享美巴黎中国电影节开幕 计划放映56部新六和社区“美德银行”开张7个月 “存法国两男子晚间持械抢劫 得价值70万英小报窃听引关注 法庭百年后解除部分\"菲特\"重创浙江海水养殖 渔业互伊拉克向美国请求军事援助 对抗“基地巴基斯坦法院再次召开针对前总统扎尔达印度总理辛格从不用手机 免遭美国监听法国和西班牙情报部门被指与美国共享电光头阳暴露大盘多头上涨已定记住这20个忠告,孩子未必成器,但一魅蓝note 2发布:mBack交互股票坚决七不买原则信用卡族投资P2P要注意了!\"狼\这个智能水壶能让你随时保持充足水分红岭创投单日成交量超5亿刷新行业纪录看见这样的走势赶紧买,不能再等了韩庚:你可能永远都看不到我站在舞台上阅读时,大脑的不同区域在干啥?中国医药网门户,安全用药小助手未来已来,千元眼纹识别新宠——么么哒感恩,或许能提高你的自制力韩红本周六深圳开唱 蒋欣叶璇送祝福大——SOLOVE素乐2X 泰坦体验有一种饿,叫“周末去了奶奶家”山西临县八堡乡600万斤优质红枣大量你要对得起自己的耳朵——Focal 天花:感恩节的隐秘历史明日大盘节节高升!加!马不停蹄的加仓企业对接公益高峰论坛最新议题公布
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘