Flux前端
耍了解 Redux,首先要从 Flux 提及,能够认为 Redux 是 Flux 思想的另 一 种实现方 式,经过了解 Flux,咱们能够知道 Flux一族框架(其中就包括 Redux)贯彻的最重要的 观点一一单向数据流,更重要的是,咱们能够发现 Flux框架的缺点,从而深入地认识到 Redux 相对于 Flux 的改进之处 。让咱们来看看 Flux 的历史,实际上, Flux是和React 同时面世的,在 2013 年, Facebook公司让 React亮相的同时,也推出了 Flux框架, React和 Flux相辅相成, Facebook认为二者结合在一块儿才能构建大型的 JavaScript应用 。作 一 个容易理解的对比, React是用来替换 jQuery 的,那么 Flux 就是以替换Backbone.js、 Ember.js 等 MVC 一族框架为目的 。mvc
在 MVC ( Model-View-Controller)的世界里, React至关于 v (也就是 View)的部分,只涉及页面的渲染一旦涉及应用的数据管理部分,仍是交给 Model 和 Controller,不过,Flux并非 一 个 MVC 框架,事实上, Flux认为 MVC 框架存在很大问题,它推翻了MVC 框架, 并用一个新的思惟来管理数据流转 。框架
首先先说一下什么是mvc框架函数
MVC 框架是业界普遍接受的一种前端应用框架类型,这种框架把应用分为三个部分:this
model(模型) 负责管理数据,大部分业务逻辑也应该放在model中编码
view(视图)负责渲染用户界面,应该避免view中涉及业务逻辑spa
controller(控制器)负责接受用户的输入,根据用户的输入调用对应的model部分逻辑,把产生的数据结果交给view部分,让view渲染出必要的输出prototype
关系图以下debug
对于 MVC 框架,为了让数据流可控, Controller应该是中心,当 View 要传递消息 给 Model 时,应该调用 Controller 的方法,一样,当 Model 要更新 View 时,也应该经过 Controller 引起新的渲染 。日志
当Facebook推出Flux时,招致了不少质疑。 不少人都说, Flux只不过是一个对数 据流管理更加严格的 MVC 框架而已 。 这种说法不彻底准确,可是 必定意义上也说明了 Flux 的一个特色:更严格的数据流控制 。
Facebook 已经无意在 MVC 框架上纠缠,他们用 Flux 框架来代替原有的 MVC 框架,他们提出的 Flux 框架大体结构是图 3-3 的模样 。
一个 Flux 应用包含四个部分,咱们先粗略了解一下:
Dispatcher,处理动做分发,维持 Store 之间的依赖关系;
Store,负责存储数据和处理数据相关逻辑 ;
Action,驱动 Dispatcher 的 JavaScript 对象
View,视图部分,负责显示用户界面。
若是非要把 Flux 和 MVC 作一个结构对比,那么, Flux 的 Dispatcher至关于 MVC 的 Controller, Flux 的 Store至关于 MVC 的 Model, Flux 的 View 固然就对应 MVC 的 View 了,至于多出来的这个 Action,能够理解为对应给 MVC 框架的用户请求 。
在 MVC 框架中,系统可以提供什么样的服务,经过 Controller暴露函数来实现 。 每增长 一个功能, Controller每每就要增长一个函数;在 Flux 的世界里,新增长功能 并不须要 Dispatcher增长新的函数,实际上, Dispatcher 自始至终只须要暴露一个函数 Dispatch, 当须要增长新的功能时,要作的是增长一种新的 Action类型, Dispatcher 的对 外接口并不用改变 。
当须要扩充应用所能处理的“请求”时, MVC 方法就须要增长新的 Controller,而 对于 Flux 则只是增长新的 Action。
1. Dispatcher
首先,咱们要创造一个 Dispatcher,几乎全部应用都只须要拥有 一 个 Dispatcher, 对于咱们这个简单的应用更不例外 。 在 src/AppDispatcher. 中,咱们创造这个惟 一 的 Dispatcher 对象,代码以下:
import {Dispatcher} from 'flux'; export default new Dispatcher();
很是简单,咱们引人 flux库中的 Dispatcher类,而后创造一个新的对象做为这个文 件的默认输出就足够了 。 在其余代码中,将会引用这个全局惟一的 Dispatcher对象。
Dispatcher存在的做用,就是用来派发 action,接下来咱们就来定义应用中涉及的 action。
2. action
ction顾名思义表明一个“动做”,不过这个动做只是一个普通的 JavaScript对象,代
表一个动做的纯数据,相似于 DOMAPI 中的事件( event)。 甚至,和事件相比, action 其实仍是更加纯粹的数据对象,由于事件每每还包含 一些方法,好比点击事件就有 preventDefault方法,可是 action对象不自带方法,就是纯粹的数据。
做为管理, action 对象必须有一个名为 type 的字段,表明这个 action 对象的类型,
为了记录日志和 debug 方便,这个 type 应该是字符串类型 。
定义 action 一般须要两个文件,一个定义 action 的类型,一个定义 action 的构造函
数(也称为 action creator)。 分红两个文件的主要缘由是在 Store 中会根据 action 类型作 不一样操做,也就有单独导人 action类型的须要 。
在 src/ActionTypes.js 中,咱们定义 action 的类型,代码以下:
export const INCREMENT = 'increment'; export const DECREMENT = 'decrement';
在这个例子中,用户只能作两个动做,一个是点击“+”按钮, 一个是点击 钮,因此咱们只有两个 action类型则CREMENT 和 DECREMENT。
如今咱们在 src/Actions. 文件中定义 action 构造函数:
import * as ActionTypes from './ActionTypes.js'; import AppDispatcher from './AppDispatcher.js'; export const increment = (counterCaption) => { AppDispatcher.dispatch({ type: ActionTypes.INCREMENT, counterCaption: counterCaption }); }; export const decrement = (counterCaption) => { AppDispatcher.dispatch({ type: ActionTypes.DECREMENT, counterCaption: counterCaption }); };
虽然出于业界习惯,这个文件被命名为 Actions.js,可是要注意里面定义的并非action对象自己,而是可以产生并派发 action对象的函数。
在 Actions. 文件中,引入了 ActionTypes 和 AppDispatcher, 看得出来是要直接使用Dispatcher。
这个 Actions. 导出了两个 action构造函数 increment和 decrement,当这两个函数被调用的时候,创造了对应的 action对象,并当即经过 AppDispatcher.dispatch 函数派发出去 。 派发出去的 action对象最后怎么样了呢?在下面关于 Store 的部分能够看到 。
3. Store
一个 Store也是一个对象,这个对象存储应用状态,同时还要接受 Dispatcher派发的 动做,根据动做来决定是否要更新应用状态 。
接下来咱们创造 Store相关的代码,由于使用 Flux以后代码文件数量会增多,再把 全部源代码文件都放在 src 目录下就不容易管理了 。 因此咱们在 src 下建立一个子目录 stores,在这个子目录里面放置全部的 Store代码。
在前面demo的 Contro!Panel应用例子里,有三个 Counter组件,还有一个统计三个 Counter 计数值之和的功能,咱们遇到的麻烦就是这二者之间的状态如何同步的问题,如今,咱们创造两个 Store,一个是为 Counter组件服务的 CounterStore,另 一个就是为总 数服务的 SummaryStore。
咱们首先添加 CounterStore,放在 src/stores/Count巳rStore. 文件中 。
const counterValues = { 'First': 0, 'Second': 10, 'Third': 30 }; const CounterStore = Object.assign({}, EventEmitter.prototype, { getCounterValues: function() { return counterValues; }, emitChange: function() { this.emit(CHANGE_EVENT); }, addChangeListener: function(callback) { this.on(CHANGE_EVENT, callback); }, removeChangeListener: function(callback) { this.removeListener(CHANGE_EVENT, callback); } });
当 Store 的状态发生变化的时候, 须要通知应用的其余部分作必要的响应 。 在咱们 的应用中,作出响应的部分固然就是 View部分,可是咱们不该该硬编码这种联系,应 该用消息的方式创建 Store 和 View 的联系 。 这就是为何咱们让 CounterStore 扩展了 EventEmitter.prototype,等于让 CounterStore成了 EventEmitter对象, 一个 EventEmitter 实例对象支持下列相关函数 。
1,emit 函数,能够广播一个特定事件,第一个参数是字符串类型的事件名称 ;
2,on 函数,能够增长一个挂在这个 EventEmitter对象特定事件上的处理函数,第一个参数是字符串类型 的事件名称,第二个参数是处理函数;
3,removeListener 函数, 和 on 函数作的 事情相反, 删 除挂在这个 EventEmitter对象特定事件上的处理函数,和 on 函数同样, 第一个参数是事件名称 ,第二个参数 是处理函数。 要注意, 若是要调用 removeListener函数, 就必定要保留对处理函 数的引用。
对于 CounterStore对象, emitChange、 addChangeListener和 removeChangeListener函 数就是利用 EventEmitter上述的三个函数完成对 CounterStore状态更新的广播 、添加监昕 函数和删 除监昕 函数等操做 。
CounterStore 函数还提供一个 getCounterValues 函数,用于让应用中其余模块能够读 取当前的计数值,当前的计数值存储在文件模块级的变量 counterValues 中
上面实现的 Store 只有注册到 Dispatcher实例上才能真正发挥做用,因此还须要增长 下列代码:
import AppDispatcher from '../AppDispatcher.js'; CounterStore.dispatchToken = AppDispatcher.register((action) => { if (action.type === ActionTypes.INCREMENT) { counterValues[action.counterCaption] ++; CounterStore.emitChange(); } else if (action.type === ActionTypes.DECREMENT) { counterValues[action.counterCaption] --; CounterStore.emitChange(); } });