Flux 普及读本
话说当时做 APP 时,三月不知肉味,再次将眼光投放前端,有种天上一天,地下一年的感觉。
Flux 是一种思想
了解的最好方式当然是看Flux官方文档了。React 中文站点也能找到对应的翻译版本,但及时性可能无法保证。
Flux不算框架,它是一种编程思想,抑或是一种程序设计范式(Design Pattern),应用架构(Application Architecture),我更习惯称它为一种思想,与前端组件化的编程思想 react 相辅相成。
It's more of a pattern rather than a formal framework,
既然只是一种范式,可以看作是程序编写过程中的一种指导,具体的实现就因人而异了。
现在世面上各种牌子的 Flux 实现都有,选择的空间很大,Which Flux implementation should I use?这个 issue 里倒是列出了一些并附上了 npm 的下载量。
我们注意到 Redux 在其中是比较瞩目的一个,之一。
虽然从最近更新的 Redux 文档来看,
Can Redux be considered a Flux implementation?
Yes, and no.
对于它是否是 Flux 的一种实现还有争论,但了解 Flux 对于我们搞清楚时下前沿技术,保持技术人员的先进性,使用 Redux,也是有帮助的。但老实说,Flux 早在2014就出现在公众视野了,到现在已算不得有多新。
Flux 与 React
React 将界面组件化,并实现了由数据驱动的层叠式更新。这过程中数据成为了程序中最为关键的一环。在传统的 MVC 模式下,React 可以看作是 View 层面的东西,而其他方面,逻辑及状态管理,则需要 React 之外的东西来接管,Flux 应运而生。
单向数据流,这些一核心理念可以和 React 很好地补充。当然也有另一层意思,Flux 不一定与 React 搭配才能用。用户在 React 组件上进行交互,视图将操作通过 Action 的形式由 Dispatcher 进行分发,各个Store 注册并接收,处理自己所负责的 Action,然后将更新重新反映到视图上。
整个流程下来,负责程序某一组件的 Store 只需要发送更新,而不用关心视图怎样根据状态来变更。这种做法很符合 React 的声明式编程风格(Declarative programming style)。
强势插入科普环节
与声明式编程相对应的是命令式编程(Imperative programming),具体来说,
- 声明式编程是告诉计算机你想要的结果,具体过程由计算机自动完成
- 命令式编程则是事先告诉计算机操作步骤,你期待的输出则可能会在程序执行完后出现
了解更多可以参见 StackOverflow 的这个提问Difference between declarative and imperative in React.js?
但是为什么说 React 是声明式的编程风格呢?想想用 React 编程的时候,你通过掌控流程和状态,告诉程序此刻应该是什么样子,而根据当前状态各视图要怎样切换,你无需多管,反正最终组合后的结果,就是你想要的样子。
Flux 的组成
是时候祭出这张图了。
Flux 的理念里,包含三个重要组成部分。Actions,Dispatcher 和 Stores。如果有第四个的话,我想可能是 Controller Views。
各部分的关系可从上图看出一二。用户的操作触发 Action,由统一的 Dispatcher 来分发,Store 接收到 Action 后各自进行处理,更新自己的数据和所负责的 View。
Actions
“我其实就一普通对象”,面对我们的镜头,Action 耸了耸肩。
是的,Action 就是一个普通的 JS 对象,里面包含了这次动作所携带的新数据。约定Action 对象里包含一个唯一标识该动作的字段(一般用常量表示),这样在 Store 接收到该 Action 时可以用来判断是否需要处理该 Action。
代码来自官方 TODO 示例里面TodoActions.js https://github.com/facebook/flux/blob/master/examples/flux-todomvc/js/actions/TodoActions.js#L20-L25
...
/**
* @param {string} text
*/
create: function(text) {
AppDispatcher.dispatch({
actionType: TodoConstants.TODO_CREATE,
text: text
});
},
...
可以说,Actions 连接了视图与 Dispathcer,负责发起一个动作来触发数据更新。这个动作可以是来自界面用户的操作,也可以是异步请求的返回。
Action 只是个普通对象,只有将它发送到 Dispathcer 才会发光发热。像上面代码中,创建一个 ToDo Item 的create
方法,便是一个封装我们的 Action,将它发送到 Dispathcer 的方法。我们称之为 Action creator。而 TodoActions.js 则是集合了很多 Action creator 的对象。这个 Action 会在用户点击「添加」按钮时调用。
我们当然可以在点击事件里直接调用 Dispather 来发送 Action,但当程序庞大的时候,这样做不利于维护。View 层面不应该直接与 Dispather 打交道,它只需要完成分内的事情:响应交互,从 Store 获取数据渲染自己。而且,这样包装的另一好处是代码更加语义化,一看便知道是创建操作,将 Actoin 的创建融合在一起,也方便管理。
Dispatcher
“你一定学过计算机原理,所以你一定知道集成总线(bus)。” 面对我们的镜头,Dispather 侃侃而谈,没有 Action 的拘谨,“对,我就是那根总线。”
一个 Flux 程序中只有唯一一个 Dispatcher。 Store 会在它上面注册回调,它将 Action 分发给所有注册过回调的 Store。它充当中央调度员的角色,管理所有的 Action 分发。
按照官方的解释,之所以 Actions 需要经过一个统一的 Dispather 进行派发,是因为大型项目下,可以方便地管理 Action 之间的依赖。实际使用中,一些操作依赖于另一个操作的完成。当我们的 Action 都经过一个地方处理后,可以很容易实现这样的依赖,Dispather 则会提供waitFor
方法供我们使用。
Dispatch 中的依赖管理示例
Store 在向 Dispatcher 注册回调时,会得到一个返回值,这个值是该回调在 Dispatcher 中的索引值,能够唯一标识该回调。
代码来自 Flux 官方文档
PrependedTextStore.dispatchToken = Dispatcher.register(function (payload) {
// ...
});
拿到这个索引值,我们便可以在waitFor
方法中指定需要等待的操作了。
case 'TODO_CREATE':
Dispatcher.waitFor([
PrependedTextStore.dispatchToken,
YetAnotherStore.dispatchToken
]);
TodoStore.create(PrependedTextStore.getText() + ' ' + action.text);
break;
上面的示例中,会在TODO_CREATE
的操作会在PrependedTextStore
和YetAnotherStore
执行完成后才开始执行。
Stores
Store 中包含了程序的状态和逻辑。可以类比 MVC 模式中的 Model。但一如官方文档所解释的那样,MVC 中的 Model 更多的是一个单独ORM对象,是对现实世界个体的抽象,比如 Person,Cat。 而 Store 则是可以看成是多种对象的组合,每个对象又只取需要的部分,它负责的是程序中一个组件中状态的管理,所以它里面的状态数据是和所负责的程序区域相关的,而并不是以 ORM 对象为单位的。
如此说来我倒觉得有点像MVVM中的 View Model。
譬如聊天框,它可能包含联系人列表中的数据,用于在输入@
的时候进行提示,也会包含富文本对象用于插入种类媒体信息,与此同时,它本身还有一个输入值的模型。总之,这个InputStore
里组装了所需的状态。
Store 向 Dispatcher 注册回调,这个回调接收 Action 作为入参。前面说道,Dispatcher接收到 Action 后会分发给所有注册过回调的 Store,所以在 Store 里,一般会有switch
语句去与 Action 中的类型进行比较,以判断是否是这个 Store 关心的 Action,Store 只对自己关心的 Action 作出反应,更新状态。
Store 更新自己后,向外派发 change
事件,controller-views 监听change 事件,从 store 获取到新数据,然后派发给所有 View 上的子节点。
关于 Store, 另一个重要的点是:Store 接收 Action 后自己处理内部的逻辑并更新相应的状态数据,一轮更新下来后所有 Store 各自井然有序,内部的状态没有对外暴露,改变的唯一方法就是通过 Action。
状态只在各自的 store 里管理,程序各组件状态的分离,可以达到高度解耦的目的。由单向数据流来驱动,一目了然。而双向绑定及不够细化的各状态,会导致一处变动,很多地方跟着变动,而这些变化都由开发者自己维护,程序复杂后便不太好掌控全局了。
关于 Controller-Views
视图很好理解,如果是用 React,视图便是组件调用形成的树上面的各个绿叶,它们是用户看到的视图。而Controller-Views,
可以结合 React 的Controlled components来理解。虽然是两样东西,但都可以理解为绑定了数据后被数据所控制,所以叫 'controller','controlled'。
严格来说,数据驱动的情况下,谁又不是被数据所绑定和控制的呢,这里 controll-views 更强调的是作为根结点,与数据源打交道的这么一个角色,这么一层视图。它监听来自 Store 的change
事件,然后向 Store 获取最新的数据,接下来把数据沿着组件树向下派发,通知各个组件更新。这里就完全进入 React 了,组件内部通过调用 setSate()
或者forceUpdate()
来重新触发render()
方法,以达到视图重新渲染的目的。
Flux 学习资料
Awesome 系列! Github 上的 awesome react 仓库里面,flux 部分。
顺便说一句,如果你要找资料,哪都不用去,直接在 github 上找该技术的 awesome 系列准没错。这个系列的特点是,内容多而全,大都还免费,缺点是在纷繁的世界里需要自己去甄别好与坏,awesome 的不一定都 awesome,适合的才是对味的。
Happy coding
Flux 普及读本的更多相关文章
- 2017.12.10《“剑锋OI”普及组多校联盟系列赛(14)#Sooke#Kornal 的课余时间 》分析报告
报告内容如下 - - [导语] ------ 太晚了,时间也紧,一切尽量从简吧 PS:本文题目来自剑锋OI 所以废话也不多说,进入正题吧,代码直接跟在题目后边儿,主要分析在代码前,次要的就写在代码后面 ...
- NOIP2016普及总结
---恢复内容开始--- 当时我说如果不出意外有385,结果就这么跪在了第二题,惨啊 本来以为发挥算正常,结果这发挥太不正常了 [T1] 水题啊[趴 注意下细节就好考你会不会写代码. [T2] 这题大 ...
- NOIP2016普及
还记得去年局部变量忘记置零coin爆零的事......结果我今年又要考一年普及[趴 最近沉迷分块莫队无法自拔,这几天才想起来我是个普及组选手 几乎没准备普及,周六上午抱抱佛脚好了...... 希望能顺 ...
- redux+flux(一:入门篇)
React是facebook推出的js框架,React 本身只涉及UI层,如果搭建大型应用,必须搭配一个前端框架.也就是说,你至少要学两样东西,才能基本满足需要:React + 前端框架. Faceb ...
- NOIP2012 普及组 T3 摆花——S.B.S.
题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...
- 【资源】NOIP2013测试数据senior/junior 普及/提高 数据
https://yunpan.cn/cRSepfcG4XX3V 访问密码 48e1 NOIP2013测试数据senior/junior 普及/提高 数据都在了
- NOIP2016普及组复赛解题报告
提高组萌新,DAY1DAY2加起来骗分不到300,写写普及组的题目聊以自慰. (附:洛谷题目链接 T1:https://www.luogu.org/problem/show?pid=1909 T2:h ...
- 【海洋女神原创】知识普及:IS版本命名规则和高低关系
经常有朋友对IS的版本命名不甚了解,有时候在交流的时候就会造成误会,在这里做一下普及. IS最早出名的版本是IS6.22,这是个非常古老的版本的,但是在IS历史上有不可磨灭的贡献. 之后很长一段时间内 ...
- 05:统计单词数【NOIP2011复赛普及组第二题】
05:统计单词数 总时间限制: 1000ms 内存限制: 65536kB 描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次 ...
随机推荐
- 03.SQLServer性能优化之---存储优化系列
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 概 述:http://www.cnblogs.com/dunitian/p/60413 ...
- Windows 常用运行库下载 (DirectX、VC++、.Net Framework等)
经常听到有朋友抱怨他的电脑运行软件或者游戏时提示缺少什么 d3dx9_xx.dll 或 msvcp71.dll.msvcr71.dll又或者是 .Net Framework 初始化之类的错误而无法正常 ...
- 【走过巨坑】android studio对于jni调用及运行闪退无法加载库的问题解决方案
相信很多小伙伴都在android开发中遇到调用jni的各种巨坑,因为我们不得不在很多地方用到第三方库so文件,然而第三方官方通常都只会给出ADT环境下的集成方式,而谷歌亲儿子android studi ...
- 代码的坏味道(14)——重复代码(Duplicate Code)
坏味道--重复代码(Duplicate Code) 重复代码堪称为代码坏味道之首.消除重复代码总是有利无害的. 特征 两个代码片段看上去几乎一样. 问题原因 重复代码通常发生在多个程序员同时在同一程序 ...
- gRPC源码分析1-SSL/TLS
引子 前几天看到微信后台团队分享了TLS相关文章,正好gRPC里TLS数据加密是很重要的一块,于是整理出了这篇文章. 在gRPC里,如果仅仅是用来做后端微服务,可以考虑不加密.本文太长,先给个大纲. ...
- 【干货分享】流程DEMO-人员调动流程
流程名: 调动 流程相关文件: 流程包.xml 流程说明: 直接导入流程包文件,即可使用本流程 表单: 流程: 图片:3.png DEMO包下载: http://files.cnblogs.com ...
- BPM流程中心解决方案分享
一.需求分析 在过去办公自动化的浪潮中,很多企业已经实施了OA流程,但随着客户的发展和对流程管理的越来越重视, 客户对流程应用需求越来越深 入,您可能面临以下需求: 1.流程功能不能满足需求,包括流程 ...
- Android AndroidRuntime类
AndroidRuntime类是安卓底层很重要的一个类,它负责启动虚拟机以及Java线程,AndroidRuntime类在一个进程中只有一个实例对象保存在全局变量,gCurRuntime中.
- Atitit.研发管理如何避免公司破产倒闭的业务魔咒
Atitit.如何避免公司破产倒闭的业务魔咒 1. 大型公司的衰落或者倒闭破产案例1 1.1. 摩托罗拉1 1.2. 诺基亚2 1.3. sun2 2. 为什么他们会倒闭?? 常见的一些倒闭元素2 2 ...
- 树莓派3B的食用方法-1(装系统 网线ssh连接)
首先要有一个树莓派3B , 在某宝买就行, 这东西基本上找到假货都难,另外国产和英国也没什么差别,差不多哪个便宜买哪个就行. 不要买店家的套餐,一个是配的东西有些不需要,有的质量也不好. 提示:除了G ...