flux详细概述

翻译:莫铭
原文地址:Flux-In Depth Overview

Flux是Facebook用来构建客户端web应用的应用框架。它使用单向数据流来补充React的可组合视图组件。它更像是一种模式,而不是一个正式的框架,你可以立即开始使用Flux,而不需要大量的新代码。

Flux应用有三个主要部分: dispatcher, stores, 和views(React 组件)。不要将他们和Model-View-Controller混为一谈。Controllers在Flux应用中是不存在的,他们以controller-views的形式存在(就是一种view,常见于层次结构的顶层,他们从stores接收数据,然后将数据向下传给他们的子孙窗体)。另外,action的生成器(dispatcher的helper函数)作为语义API用来描述应用中可能出现的变化)。为方便理解也可以将它们视为Flux更新循环中的第四部分。

Flux避开MVC,而更倾向于单向数据流。当用于与React view交互时,view会通过dispatcher将action传递给每个store(这些store持有应用的数据和业务逻辑,并且更新那些受影响的views)。 这与React的声明式编程风格特别相似,它允许store发送更新,而无需指定如何在states之间转换views。

我们从恰当地处理派生数据开始:比如,我们想显示消息线程的未读信息数,而另一个视图显示线程列表,高亮显示出那些有未读消息的线程。使用MVC处理这种情况就比较困难(标记一个线程可读,将会更新线程模型,进而需要更新未读数模型)。这些依赖和级联更新在大型的MVC应用中经常发生,致使数据流错综复杂,以及不可预测的结果。

Control和stores是相反的:stores接收更新,并根据需要进行调整,而不是依赖外部以固定的方式来更新它的数据。只有store自己(内部)才知道如何管理它所管理的数据,这有助于保持清晰的职责划分。Stores没有直接的setter函数(比如setAsRead()),取而代之的是在dispatcher中注册回调函数,来获取新的数据。

结构与数据流

Flux应用中的数据单向流动:



单向数据流是Flux模式的核心,上图应该是Flux程序员心中主要的模型。dispatcher,stores和views是具有清晰输入和输出的独立节点。actions是一个简单的objects,包含新数据和一个标识类型的属性。

views会根据用户的交互,生成一个新的action在系统中传播:



所有数据流经作为中央集线器的dispatcher。Actions通常来自于用户与视图的交互,并且在一个action创建器函数中提交给dispatcher。然后dispatcher调用store已经在dispatcher中注册好的回调函数,store会回应那些与它维护的state相关的actions。然后,stores会发出一个更改事件,来告知controller-views,数据层发生了变化。Controller-views监听这些事件,并在一个事件处理器(event handler)中从store获取数据。controller-views调用他们自己的setState()函数,引起自身以及组件树中自己的后代的重新渲染。


这种结构让我们很容易理解我们的应用,以功能反应式编程或者数据流式编程的方式,数据在应用中以固定的方向流动,而不是双向绑定。应用state只在store中维护,从而使应用的不同部分保持高度解耦。依赖只发生在store之间,通过dispatcher管理的同步更新,确保他们被留在严格的层次结构中。

我们发现双向数据绑定会导致级联更新,也就是改变一个对象,将会导致另一个对象的改变,进而触发更多的更新。随着应用规模的增长,这些级联更新将会导致用户交互结果的不可预测。但如果更新只会在一轮内更改数据,整个系统就会变得更加可预测。

让我们仔细看看Flux的各个部分。dispatcher是一个好的切入点。

单独的Dispatcher

在一个Flux应用中,dispatcher是管理数据流的中央枢纽。它并没有真实的智能,本质上只是一个回调到store的注册表。每个store注册自己,并提供一个回调函数。当一个action创建器将一个新的action提供给dispatcher,应用中所有的stores,通过注册的回调函数接收到该action。

随着应用规模的增长,dispatcher变得更为重要,因为它可以通过这些注册的回调函数,不同的调用顺序,来管理stores间的依赖关系。store可以声明式的等待其他store完成更新后,再相应的更新自己。

Facebook在产品用用到的同款dispatcher现在可通过npm, BowerGitHub获得。

Stores

Stores拥有应用的state和逻辑。他们的角色有点类似于传统MVC中的模型model,但是他们管理很多对象的状态,不过不像ORM模型,他们不代表一条单独的记录数据。它们与Backbone的集合也不相同。除了简单的管理ORM风格的对象集合外,store管理应用中特定域的应用状态。

比如,Facebook的视频回放编辑器利用一个TimeStore管理回访时间点和回放状态。另一方面,应用的ImageStore管理图片集合。在我们TodoMVC示例中的TodoStore和他们差不多,它管理一个待办项集合。一个store展现出的特性就是模型的集合和一个逻辑模块单件。

如上所述,一个store通过dispatcher注册自己,并提供一个回调函数。这个回调函数接收action作为参数。在store注册的这个回调中,通过switch语法,判断action的类型,用来区分action,来调用store的内部方法。在store更新后,他们广播一个事件,来生命他们的状态发生了改变,致使views可以查询到新的状态,然后更新自己。

Views和Controller-Views

React提供了视图层所需的可组合且可自由重新绘制的视图。在嵌套的视图层次结构顶部,一种特殊的视图监听器,监听那些依赖的store所广播的事件。我们称其为controller-view,因为它提供了粘合代码,用来从stores获取数据,然后将这些数据向下传给它的后代链。我们可能会有一个用来管理页面中任何重要部分的controller-view。

当它从store接收事件,它首先通过store公开的getter函数请求它需要的新数据。然后调用自身的setState()或forceUpdate()函数,致使运行自身的render()函数和它所有子孙的render函数。

我们一般将store的整个状态放在一个单独的对象中沿着view链向下传递,允许不同的子孙使用他们需要的数据。除了将类似controller的行为保留在层次结构的顶部,我们还要尽可能的使我们的后代视图尽可能的只是功能,将store的整个状态放在一个单独的对象中向下传递,也有助于减少我们需要管理的props的数量。

偶尔我们可能也需要在更深的层次结构中添加额外的controller-views来保持组件的简单。这会帮助我们更好的封装层次结构中与特定数据域相关的部分。然而请注意,深层次的controller-views可能会由于引入了新的数据流入口,从而违背单一数据流的原则。在决定是否添加深度控制器视图时,需要在获取更简单的组件和不同点流入层次结构的多数据更新的复杂性进行之间进行平衡。这些多数据更新将导致奇怪的效果,由于React的渲染函数被不同的controller-views重复的更新调用,从而可能增加调试的复杂度。

Actions

dispatcher公开一个方法,让我们触发一个派送到stores,并且包含一个装载的数据,我们称其为action。action的创建可以被包装在一个语义helper函数中,将action发送到dispatcher。比如,在一个待办列表应用中,我们打算改变一个待办项的文本。我们可以在我们的TodoActions模块中创建一个action以及一个函数签名为updateText(todoId, newText)的函数。整个函数可以在我们的视图事件处理器中调用,这样我们就可以在用户交互的响应中调用到它了。这个action创建函数也可以添加一个类型到action中,这样当store解析它时,可以得到适当的处理。在我们的李子中,这个类型可以命名为TODO_UPDATE_TEXT.

Actions也可能来自其他地方,比如服务器。比如,发生在数据初始化时。也可能放生在服务器返回一个错误码或服务器提供更新给应用。

Dispatcher哪?

正如之前所提到的,dispatcher也可以管理stores间的依赖。可以用Dispatcher类的waitFor()函数来实现此功能。在TodoMVC application这么简单的应用中,我们确实不需要使用这个方法,但在更为大型和复杂的应用中,他非常的重要。

在TodoStore注册的回调函数中,我们可以明确的等待依赖项先去更新,然后自己再往下执行:

case 'TODO_CREATE':
  Dispatcher.waitFor([
    PrependedTextStore.dispatchToken,
    YetAnotherStore.dispatchToken
  ]);

  TodoStore.create(PrependedTextStore.getText() + ' ' + action.text);
  break;

waitFor()接收一个单独的参数,该参数是dispatcher注册索引数组,通常被称作dispatch令牌。因此,调用waitFor()的store可以依赖另一个store的状态来了解如何更新自己的状态。

一个dispatch令牌是向Dispatcher注册回调函数时由register()返回的:

PrependedTextStore.dispatchToken = Dispatcher.register(function (payload) {
  // ...
});

更多关于waitFor(),actions,action创建器和dispatcher,请查阅Flux:Actions和Dispatcher.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 去年翻译的flux官方文档对flux架构的描述,觉得最近很多朋友开始react编程了,所以我觉得有必要拿出来这篇水...
    余歌_非鱼阅读 2,494评论 0 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 夏荷零落桂枝香,秋水潮青苦荻长。寒蝉犹吟杨柳曲,冷雨染罢梧桐黄。
    江南烟雨阅读 499评论 1 22
  • 今天看了锦明老师的文章《要孩子改变,就必须先改变家长的聚焦总倾向》,认真读完了锦明老师这篇文章,再一次体会到改变自...
    不忘初心坚持到底阅读 132评论 0 2
  • 内容来自微博,自己收藏起来,用的时候更方便。
    贺頓阅读 308评论 0 1