概述
Flux是Facebook用于开发客户端WEB应用程序的产品框架,它利用单向数据流补充反馈UI信息。它更像是一个模式而不是一个正式的框架,并且你还可以使用Flux做快速开发,从而减少编写很多不必要的代码。
Youtube上的关于Flux的视频链接
Flux由三个主要部分组成:dispatcher、stores、views(反馈组件)。这些不要与Model-View-Controller设计模式搞混。Flux应用程序确实存在控制器(Controller),但他们是控制-视图(controller-view) UI通常在结构的顶层,它接收来自stores的数据并向下传递给它的子结构。此外动作的创建者会调度它的帮助方法(helper methods)来支持一些语义API,这样就可以描述应用程序可能发生的所有变化。他们被有效的认为是Flux更新循环的四部分之一。
Flux避开了MVC设计模式,使用一个单向数据流进行了取代。当用户点击一个具有交互功能的UI的时候,UI会通过中心dispatcher广播一个活动事件,分发到各个stores中,它持有应用程序的数据和业务逻辑,从而更新所有受影响的UI。这种工作方式是特别好的反馈式设计风格,这样允许store发送、更新而不用指明如何过渡UI的两个状态。
我们最初想正确的处理派生数据:例如,我们要为一个消息线程显示未读计数,而另一个界面显示线程列表并且对未读进行标注。这种情况很难运用MVC模式处理---标记单个线程为已读并更新线程模式,并且这时候还需要去更新未读计数模式。这些依赖关系和级联更新通常发生在一个大的MVC应用程序中,导致一个编织交错的数据流并且无法预支结果。
反被stores控制:stores接收更新并以适当的方式处理,而不是依赖于外部使用一些不变的方法去更新。在store之外不会观察到其内部是如何管理自身域数据的,有助与保持一个清晰的分隔关系。Stores没有直接的设置器方法类似setAsRead(),但是取而代之的是仅使用一个方式来获得新数据进入他们的内部世界(self-contained world),回调那些通过dispatcher注册的callback。
结构和数据流
Flux应用程序内部的数据单方向流动:
![Facebook Flux 教程之(一)概述_第1张图片](http://img.e-com-net.com/image/info8/354e5f8c788b4060aefcc86f6a0e524c.jpg)
单向数据流是Flux设计模式的核心,上图应当是Flux程序员的基本心里模式。dispatcher,stores和views是独立的使用不同输入和输出的节点。actions事件是一个包含新数据和标示类型属性的简单对象。
UI与用户交互的时候会产生新的action事件传入系统:
![Facebook Flux 教程之(一)概述_第2张图片](http://img.e-com-net.com/image/info8/0c5136e34c2f45e49720c88eea8892ba.jpg)
所有的数据流通过dispatcher作为中央枢纽。所有的actions事件通过action creator(action事件创建者)的方法提供给dispatcher,是用户与UI的交互是最为主要的原始来源。这时候dispatcher调用stores先前在其自身注册的callback,调度actions事件到所有的stores中。在他们注册的回调内部,stores会处理任何与他们维护状态相关的actions事件。这时stores会向控制视图(controller-views)发出一个变更事件(change event)的提示,用于提示数据层已经发生了变化。控制视图监听这些事件并且接收来自stores事件句柄中的数据。控制视图调用自身的setState()方法,引发从新重新渲染他们自己,以及所有他们继承树中的子组件。
![Facebook Flux 教程之(一)概述_第3张图片](http://img.e-com-net.com/image/info8/6a46967b0b3241dfa2c137c18cfb4374.jpg)
这种结构在某种程度上让我们很容易理解应用程序,回想反应式功能编程,或更具体的数据流编程或者基础流编程,数据流以单向的方式贯穿应用程序,这里没有双向的绑定流。应用程序的状态仅被stores进行维护,允许应用程序的不同部保持高度解耦。这里依赖stores之间的相互作用,他们被保持在一个严格的层级中,由dispatcher进行同步更新管理。
我们发现双向数据绑定会导致级联更新,这里改变一个对象导致另一个对象也跟着改变,这可能引发更多的更新。随着应用程序的开发,这些级联更新非常难预测在和用户交互中将要发生的结果。当更新仅能改变单向数据流动中的数据,整个系统将变得更加容易预测。
让我们全方位,近距离的观察Flux。dispatcher是一个好的开始。
单个Dispatcher
在Flux应用程序中dispatcher是管理所有数据流的中央枢纽。它实质上就是一个注册到stores上的回调并且自身却没有真实的能力,它是散发actions事件到stores的简单机制。每个store会注册他自己并提供一个回调。当一个action创建者为dispatcher提供一个新的action事件时,在这个应用程序中的所有stores都会通过注册的回调接收到actions事件。
作为一个应用程序的不断开发,dispatcher会变的更加至关重要,因为它被用于管理store注册的回调被调用的特定顺序。stores可以声明成等待另一个stores更新完成,再更新它自己。
在Facebook产品中使用相同的dispatcher可以通过 npm, bower或者 GitHub。
Stores
stores包含应用程序的状态和逻辑。他们的角色类似于传统的MVC模型,但他们管理很多对象的状态,他们并不扮演类似于ORM模型所做的单一数据记录。他们也不是一样的骨干集合。更不是简单的管理ORM类型对象的集合,stores管理应用程序内部特定 领域应用的状态。
例如,Facebook的 Lookback Video Editor利用一个时间store保持回放时间、位置和回放状态的轨迹。在另一方面同一个应用程序的图片store保持图片集合的轨迹。这和我们 待办MVC模型例子中的待办store例子是相似的,管理一个待办项集合。
如上所述,store在dispatcher中注册它自己并提供一个回调。这个回调接收Action事件作为参数。在store注册的回调中,一个基于action事件类型,解释action事件并且转换提供合适的钩子到store的内部法中。这允许一个action事件经过dispatcher引发对store状态的更新。stores更新后,他们广播一个状态已经改变的事件声明,所以UI会询问新的状态并更新他们自己。
UI 和控制-视图
反馈提供了我们需要的UI层重复渲染的自由组合。聚焦嵌套UI的顶层,一个特殊类型的UI依靠监听stores的广播事件,我们叫这是控制-视图(controller-view),它用于将代码和来自stores的数据进行粘合并且沿继承链向后代传递这些数据。我们可能有一个这样的控制-视图控制页面中一些特殊的部分。
当它接到来自store的事件的时候,它首先要求新数据访问stores的公共方法getter。然后它调用自己的 setState()或者 forceUpdate()方法。导致 render()方和 redener ()方法的后代方运行。
我们通常沿着UI链使用一个对象贯穿整个store的状态,允许不同的后代使用他们所需要的一切。除了保持顶层控制器行为之外,尽可能的保持子UI功能简单。通过使用单个对象沿着整个store的状态运行也可以有效的减小需要管理的工具项。
偶尔我们需要在深层添加额外的控制-视图来保持组件简单。这可以帮助我们更好的封装层中相关特定的数据域。注意到在被引入到深层的控制-视图会阻碍单向数据流,是数据流的潜在冲突入口点。要做出是否在深层添加控制-视图的决定,在不同点上要平衡增强简单的组件反对复杂多项的数据更新流进入层级。这些多项数据更新会导致古怪效果,反馈模式提供的方法会受到不同的控制-视图反复的更新,为程序debug增加难度。
Actions事件
dispatcher暴露一个方法这个方法允许我们触发调度stores,并且包含一个有效负载对象,我们称做一个action事件。action的创建可以包含到发送acton事件的调度帮助方法中。例如我们要修改应用程序to-do列表中的一个文本中的to-do项目。在我们的 TodoActions模式中,我们将创建一个action事件使用类似函数 updateText(todoId, newText)的功能。这个方法可能被UI事件的操作者调用,所以我们能在相应用户的交互中调用它。这个action事件创建方法也会为action事件添加一个类型,所以当action事件进入store的时候可以被理解,可以做出适当的回应。在我们的例子中,这个类型可能被命名为 TODO_UPDATE_TEXT。
actions事件也可能来自其他地方,比如服务器。,例如数据初始化期间会发生这种情况。也可能发生在服务器返回错误代码,或者服务器更新用于程序的时候。
如何调度呢?
如上所述,dispatcher也可以管理与stores之间的依赖关系。这个功能可以通过Dispatcher类中的waitFor()方法实现的。我们在极其简单的TodoMVC应用程序中不需要使用这个方法,但它在更大、更复杂的应用程序中变得至关重要。
在TodoStores注册的回调内部,我们明确等待任何依赖去推进第一个更新:
case 'TODO_CREATE':
Dispatcher.waitFor([
PrependedTextStore.dispatchToken,
YetAnotherStore.dispatchToken
]);
TodoStore.create(PrependedTextStore.getText() + ' ' + action.text);
break;
waitFor()接收单个dispatcher注册索引列表作为参数,经常称作调度令牌(
dispatch tokens)。这时store被waitFor()调用可以依赖另一个store的状态来告知如何更新自己的状态。
调度令牌是通过在Dispatcher注册回调时,通过register()方法返回。
PrependedTextStore.dispatchToken = Dispatcher.register(function (payload) {
// ...
});
欲了解更多关于waitFor(),actions事件、action事件创建者和dispatcher,请参看
Flux: Actions and the Dispatcher
.
原始链接https://facebook.github.io/flux/docs/overview.html