网站首页 > 技术文章 正文
我该用Flux吗?
作为一个小白,Flux很不直观,也没有很多入门级文档,没有明确的解释。在我摸索学习 Flux 的时候,有人能告诉我下面这些东西。我该用Flux吗?
如果你的应用使用了 动态数据 那么 你应该用Flux。
如果你的页面只是 静态页面 不共享状态,你不需要保存和上传数据,你不需要用Flux,Flux不会给你带来好处。
为什么是Flux?
幽默的说,因为Flux是一个相对难懂,复杂的概念。为什么要增加复杂度呢?
90% 的IOS应用把 数据传入table view IOS封装了很好的视图组件,数据模型,让开发者轻松的开发。
在前端开发中(HTML, Javascript, CSS),我们没有这样的概念。也就是说我们要面对一个大问题: 我们不知道该如何构建一个前端应用程序。我入行多年,没有人探讨“最佳实践”。反而是探讨类库,比如jQuery,Angular,Backbone,但是我们逃避了最重要的问题,数据流。
什么是Flux?
Flux 是一个名词,主要描述一种用特别的事件和监听器处理数据流的方式。这里没有官方的Flux类库,但是你需要用到 Flux Dispatcher和event library。
官方文档写的好像某个人脑子里的意识流,这并不是一个适合作为初学者起步的文档,只有当深入了解Flux时,才能理解作者,脑补作者没写的内容。
不要试图比较 Flux 和 MVC 架构,这只会让你更加混淆。
让我们开始吧,这次我将 逐个解释概念。
1. Views层"Dispatch" "Actions"(分发操作)
dispatcher本质是一个添加了额外规则的事件系统。它分发事件并定义回调函数。 只能定义一个全局的dispatcher。你可以使用Facebook的类库 Dispatcher Library。举个例子:
`var AppDispatcher = new Dispatcher();`
比方说有一个“新建”按钮,点击按钮把item添加到一个列表中。
`New Item`
What happens on click? Your view dispatches a very specific "action", with the action name and new item data:
点击后会发生什么?View 层触发一个特定事件,包括item名和item的数据:
createNewItem: function( evt ) { AppDispatcher.dispatch({ actionName: 'new-item', newItem: { name: 'Marco' } // example data });}
"action" 是Facebook创造的另一个词。action一个Javascript对象,表示我们想做的动作,和我们需要的数据。如上所述,我们想创造一个new-item,我们需要的数据是 name。
2. "Store" 响应 Dispatched Actions (被分发的事件)
For our application, we need a specific collection of logic and data for the list. This describes our store. We'll call it a ListStore.
Flux中"store" 也是一个Facebook创造的名词。我们的应用中,我们需要一个集合存放状态,我们叫它ListStore。
Store 就是一个单例,意味着你不需要 new 出来。ListStore 就是一个全局的对象:
// Single object representing list data and logicvar ListStore = { // Actual collection of model data items: []};
然后 Store 响应分发出来的事件:
var ListStore = …// Tell the dispatcher we want to listen for *any*// dispatched eventsAppDispatcher.register( function( payload ) { switch( payload.actionName ) { // Do we know how to handle this action? case 'new-item': // We get to mutate data! ListStore.items.push( payload.newItem ); break; }});
这就是传统的Flux处理分发事件回调函数的方式。payload 包含一个事件名和数据。使用 switch 语句来决定调用哪个操作,是响应回调,还是改变数据,还是其他。
核心观点: Store 不是 model,而是 model 的容器。
核心观点: 应用中唯一知道如何更新数据的就是 Store。这是 Flux 最重要的一部分。我们分发的事件是不知如何添加或者删除条item。
再比如,应用的其他部分需要保存图片和它们的元数据,你需要使用另外一个 Store,可以取名为 ImageStore。一个 Store 就代表了应用的一个单独的域。如果应用足够大,那么下呢按划分区域。如果应用不大,那很可能只需要一个 Store。
只有 Store 可以注册 callback。View 永远都不应该调用 AppDispatcher.register。Dispatcher 的存在就是为了把消息从 View 传递到 Store。而 View 则是响应另外一种事件。
3. Store 触发 “change” 事件
现在数据已经变化了,我们要通知其他部分。
Store 触发一个事件,但不使用 Dispatcher。这也许会让你混淆,不过这就是 Flux 的方式。下面我们给Store添加event,如果你使用 MicroEvent.js ,可以这么写:
`MicroEvent.mixin( ListStore );`
接下来就是触发事件:
case 'new-item': ListStore.items.push( payload.newItem ); // Tell the world we changed! ListStore.trigger( 'change' ); break;
核心观点: 就单单触发事件,不传递最新的item。View 只关心是不是有内容改变了。下面我会说一下原因。
4. View 层响应 “change” 事件
现在我们需要展示列表了,当列表变化的时候,View会完全重绘。
首先,当 Component “上马”的时候,监听 ListStore 的 change 事件,就是在 Component 创建时:
componentDidMount: function() { ListStore.bind( 'change', this.listChanged );},
简单点,直接调用 forceUpdate,触发重绘。另外一种方式,就是把整个列表保存在 state 中。
listChanged: function() { // Since the list changed, trigger a new render. this.forceUpdate();},
当 Component加载完时,记得清除监听函数,也就是在 Component 调取回调函数的时候:
componentWillUnmount: function() { ListStore.unbind( 'change', this.listChanged );},
接下来该做什么?看看我们的Render函数,我有意把它放到最后:
render: function() { // Remember, ListStore is global! // There's no need to pass it around var items = ListStore.getAll(); // Build list items markup by looping // over the entire list var itemHtml = items.map( function( listItem ) { // "key" is important, should be a unique // identifier for each list item return
{ listItem.name }
; }); return
{ itemHtml }
New Item
;}
整个流程就是这样。当你添加以一个item,View item触发一个行为,Store 对这个行为作出相应,Store 更新,Store 触发 change 事件,接着 View 响应这个 change 事件重绘。
但是有一个问题:每次列表变化的时候都重绘整个 View,那样效率低的可怕。
不是。
没错,render 函数确实被调用了,render 函数中所有代码都一次次的执行了。但是只有在 DOM 真正变化的时候 React 才把变化 render 出来 。render 函数生成了一个虚拟DOM,React 会对比之前一次 render 出来的 DOM。如果这两次的虚拟DOM不一样,React 就更新真实 DOM 中变化的部分。
核心观点:当 Store 变化时,View 无需关心条目是添加、删除,还是修改了。它只需要整个重绘,React 的“虚拟DOM”算法进行复杂的运算,找出哪些真实的DOM节点变化了。这可以帮助你简单生活,不再紧张。
补充: 该死的 "Action Creator" 是什么?
你应该还记得,点击按钮,触发事件:
AppDispatcher.dispatch({ eventName: 'new-item', newItem: { name: 'Samantha' }});
不过,如果 View 中有很多地方都需要触发这个事件,这就太冗余了。而且,所有的 View 都需要知道事件对象的特定格式。这样有些别扭。Flux 提出一个抽象的层,叫做行为action creators(创建器),其实就是把上面的代码放到一个函数中。
ListActions = { add: function( item ) { AppDispatcher.dispatch({ eventName: 'new-item', newItem: item }); }};
现在 View 只需要调用ListActions.add({ name: '...' });,不用关心分发对象的语法了。
没有回答的问题
所有关于Flux的文章,大多告诉我们如何管理数据流,但是并没有解答如下问题:
如何加载,保存数据并更新到服务端?
在不用父组件的情况下,组件之间如何通信?
What events library should I use? Does it matter?
我应当使用哪个events library?这是否很重要?
为什么Facebook没有把Flux相关的类库打包成一个类库?
Should I use a model layer like Backbone as the model in my store?
我是否可以使用一个数据层代替store,比如Backbone的model?
这些问题的答案是: 开心就好!
PS: 不要使用强制刷新
我使用了 强制更新 的目的仅仅是为了简单举例。正确的更新视图方法是,读store里的数据, 复制数据到state通过读this.state 再调用render函数更新。你可以看这个例子。 TodoMVC example.
当模板第一次加载时, store数据被复制 到state. 当store更新, 数据再次被完全复制。这样会更好,因为它只在内部, 强制更新是同步的,通过setState效率更高。
以上!
作为附加资源,可以查看Facebook提供的Example Flux Application 。希望看过这个 the files in thejs/ folder will be easier to understand.
Flux文档包含一些高级技巧,还有一些深层的内容。
猜你喜欢
- 2024-09-26 vue3新特征和所有的属性,方法汇总及其对应源码分析
- 2024-09-26 git仓库删除所有提交历史记录,成为一个干净的新仓库
- 2024-09-26 react相关基础知识(react教程,看这篇就够了)
- 2024-09-26 Vue2与Vue3的数据响应式区别(vue3和vue2的优缺点)
- 2024-09-26 关于Vue和React的一些对比及个人思考(中)
- 2024-09-26 我为LowCodeEngine低代码引擎写了个插件
- 2024-09-26 深入浅出 React V16.4 生命周期的来龙去脉
- 2024-09-26 CharIN有关充电功率的规划(充电功率计算充电时间)
- 2024-09-26 「前端」线上紧急问题排查工具(纪委问题线索处置和自查自纠情况报告)
- 2024-09-26 解析!Android内存优化工具(android如何节省内存优化)
- 1515℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 579℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 515℃MySQL service启动脚本浅析(r12笔记第59天)
- 487℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 486℃启用MySQL查询缓存(mysql8.0查询缓存)
- 471℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 450℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 448℃MySQL server PID file could not be found!失败
- 最近发表
-
- 宝塔面板Nginx如何提高网站访问速度?
- 接口调试工具ApiPost中form-data/x-www-form-urlencoded/raw区别
- 高并发场景下,Nginx性能如何提升10倍?
- 高并发场景下,Nginx如何抗住千万级流量?
- 浏览器中在线预览pdf文件,pdf.mjs插件实现web预览pdf
- 为什么你的网站加载慢?90%的人忽略了这2个设置。
- 别再无脑复制Nginx配置了!掌握这10个"性能核弹"级参数
- 你的Nginx配置,可能就是你网站最慢的一环,注意这几个优化参数
- 深入浅出HTTP压缩技术(http2压缩)
- C程序设计之:1-1/2+1/3-... + 1/n 的和
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (83)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)