react flux

Overview

为了方便理解,主要的英文名词都没有翻译。好比:dispatcher(调度者)、 store(仓库)、view(视图)程序员

Flux是Facebook用来构建用户端的web应用的应用程序体系架构。它经过利用数据的单向流动为React的可复用的视图组件提供了补充。相比于形式化的框架它更像是一个架构思想,不须要太多新的代码你就能够立刻使用Flux构建你的应用。web

Flux应用主要包括三部分:dispatcher、store和views(React components),千万不要和MVC(model-View-Controller)搞混。Controller在Flux应用中也确实存在,可是是以controller-view的形式。view一般处于应用的顶层,它从stores中获取数据,同时将这些数据传递给它的后代节点。另外,action creators - dispatcher辅助方法 - 一个被用来提供描述应用全部可能存在的改变的语义化的API。把它理解为Flux更新闭环的第四个组成部分能够帮助你更好的理解它。npm

Flux使用单向的数据流动来避开MVC. 当用户与React视图交互的时候,视图会经过中枢dispatcher产生一个action。而后大量的保存着应用数据和业务逻辑的视图接收到冒泡的action,更新全部受影响的view。这种方式很适合React这种声明式的编程方式,由于它的store更新,并不须要特别指定如何在view和state中过渡。编程

咱们首创性的解决了数据的获取:举个栗子,好比咱们须要展现一个会话列表,高亮其中未读的会话,同时展现未读会话的数量。若是用MVC架构的话将很难处理这种状况,由于更新一个对话为已读的时候会更新对话model,而后一样也须要更新未读对话数量model(数量-1)。这样的依赖和瀑布式的更新在大型的应用中很是常见,致使错综复杂的数据流动和不可预测的结果。(这实际上是Facebook以前的一个线上bug,有时候用户看到提示说有一条未读信息,可是点进去却发现没有)。数组

反过来让 Store 来控制:store接受更新,并在合适的时机处理这些更新。而不是采用一向依赖外部的方式来更新数据。在store外部,并没办法看到store内部是如何处理它内部的数据的,这样的方式保证了一个清晰的关注点分离。Store并无相似setAsRead()这样直接的setter方法,可是在其自成一体的世界中拥有惟一个获取新数据的方法 - store经过dispatcher注册的回调函数。服务器

Structure and Data Flow

在Flux应用中数据是单向流动的:架构

unidirectional data flow in Flux

 

单向的数据流是Flux应用的核心特性,上图应该成为Flux程序员的主要心智模型。Dispatcher,stores和views是拥有清晰的输入输出的独立节点。而actions是包含了新的数据和身份属性的简单对象。框架

用户的交互可能会使views产生新的action,这个action能够在整个系统中传播:编辑器

unidirectional data flow in Flux

全部的数据的流动都经过中枢dispatcher。Action能够经过action creator产生并被提供给dispatcher,但多数状况下action是经过用户与views的交互产生。dispatcher接收到action并执行那些已经注册的回调,向全部stores分发action。经过注册的回调,store响应那些与他们所保存的状态有关的action。而后store会触发一个 change 事件,来提醒controller-views数据已经发生了改变。Controller-views监听这些事件并从新从store中获取数据。这些controller-views调用他们本身的setState()方法,从新渲染自身以及组件树上的全部后代组件。函数

unidirectional data flow in Flux

这种的响应式编程,或者更准确的说数据流编程亦或基于数据流的编程,可使咱们很容易去推断咱们的应用是如何工做的。由于咱们的应用中数据是单项流动的,不存在双向绑定。应用的状态只保存在store中,这就容许应用中不一样部分保持高度的低耦合。虽然依赖在store中也确实存在,但他们之间保持着严格的等级制度,并经过dispatcher来管理同步更新。

咱们发现双向绑定会致使瀑布式的更新,一个对象发生变化会引发另外一个对象的改变,并可能致使更多的更新。随着应用的增大,这些瀑布流式的更新方式会使咱们很难预测用户交互可能会致使的改变。当更新只能以单一回合进行的时候,系统的可预测性也就会变得更高。

让咱们来看看Flux的各个部分。先从diapatcher开始会比较好

A Single Dispatcher

dispatcher 就像是一个中央的集线器,管理着全部的数据流。本质上它就是 store callback 的注册表,自己并无实际的高度功能。它就是一个用来向stores分发actions的机器。 每个 store 各自注册本身的 callback 以提供对应的处理动做。当 dispatcher 发出一个 action 时,应用中全部的store都会经过注册的callback收到这个action。

随着应用的增加,dispatcher会变得更加必不可少,由于它可以指定注册的callback的执行顺序来管理store之间的依赖。store能够被声明等待其余store完成更新以后,再执行更新。

Facebook目前在生产环境中使用的flux能够分别在npm, Bower,or Gihub中获取。

Stores

Stores 包含了应用的状态和逻辑,它有点儿像传统MVC中的model层,可是却管理着多个对象的状态 - 他们不像传统的ORM model 只管理单个的数据记录,和backbone中的collection也不同。

举个栗子,Facebook的回看视频编辑器使用TimeStore来保存播放时间和播放状态。另外,应用中的ImageStore保存着图片的集合。再好比说咱们的TodoMVC示例中,TodoStore也相似地管理着to-do items的集合。store典型的特征就是既是models的集合,又是所属业务域下的model实例。

就像上面所说的,store在dispatcher中注册,并提供相应的回调。回调会接收action并把它当成本身的一个参数。当action被触发,回调函数会使用switch语句来解析action中的type参数,并在合适的type下提供钩子来执行内部方法。这就容许action经过dispatcher来响应store中的state更新。store更新完成以后,会向应用中广播一个change事件,views能够选择响应事件来从新获取新的数据并更新。

Views and Controller-Views

React提供了一种可组合式的view让咱们能够自由组合展现层。在接近顶层的地方,有些view须要监听所依赖的store的广播事件。咱们称之为controller-view,由于他们提供了胶水代码来从store中获取数据,并向下层层传递这些数据。咱们会利用这些controller-views来处理页面上某些重要部分。

当它接收到store的广播事件后,它首先会经过store的公共getter方法来获取所需的数据,而后调用自身的setState() 或 forceUpdate()方法来促使自身和后代的从新渲染。

在单一实例中,咱们一般会向后代view传递所有数据,而让他们本身从中提取所需数据。此外咱们在结构的顶部也维持着相似controller的行为,而且让后代的view保持的function特性。经过向后代传递全部的数据,也有助于减小咱们须要管理的props的数量。

偶尔,咱们须要在系统的更深层的地方加入controller-views来保持咱们的组件的简单。这有助于封装一个特定的数据域下的相关部分。须要注意的是,系统深层的controller-views可能会影响数据的单向流动,由于他们可能会引入一些新的,潜在的存在冲突的数据流入口。在决定是否增长深层的controller-views时,咱们须要多方面权衡简单的组件和复杂多样的数据更新流这两点。这些多样的数据更新可能会致使一些古怪的反作用,伴随着不一样的controller-views的render调用,潜在的增长了Debug的难度。

Actions

dispatcher提供了一个能够容许咱们向store中触发分发的方法,咱们称之为action。它包含了一个数据的payload。action生成被包含进一个语义化的辅助方法中,来发送action到dispatcher。好比,咱们想更新todo应用中一个todo-item的文本内容。咱们会在TodoActions模块中生成一个相似updateText(todoId, newText) 这样的函数,这个函数能够被视图事件处理调用执行,所以咱们能够经过调用它来响应用户交互。action生成函数一样会增长一个type参数,根据type的不一样,store能够作出合适的响应。在咱们的例子中,这个type能够叫作TODOUPDATETEXT。

一个payload大概是这个样子的: { source: "SERVER_ACTION", action: { type: "RECEIVE_RAW_NODES", addition: "some data", rawNodes: rawNodes } }

Actions也可能来自其余地方,好比服务器端。这种状况可能会在数据初始化的时候出现,也多是当服务器视图更新的时候返回了错误的时候出现。

What About that Dispatcher?

就像以前提到的那样,dispatcher也能够用来管理store之间的依赖。咱们能够经过dispatcher的waitFor()方法来实现。在相似TodoMVC这样简单地应用中咱们可能用不到这个方法,可是在更大型,更复杂的应用的它会变得不可或缺。

在执行TodoStore的注册回调时,咱们能够明确地等待任何依赖先更新,而后再进行后续的处理:

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

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

waitFor()的参数是一个包含了dispatcher注册索引的数组,这个索引一般被称之为dispatch tokens。所以store可使用waitFor()来依赖其余的state,以此来肯定如何更新它本身的state。

使用register()方法注册回调的时候会返回一个id,这个id能够用做dispatch token

PrependedTextStore.dispatchToken = Dispatcher.register(function (payload) {
  // ...
});
相关文章
相关标签/搜索