Flux

栏目: 后端 · 发布时间: 7年前

内容简介:Flux

一.定位

一种模式,用来强化单向数据流(unidirectional data flow)

二.作用

剥离数据层,让数据可预测(React让UI可预测,Flux让数据可预测)

具体做法:

  • 用显式数据,不用衍生数据(先声明后使用,不临时造数据)

  • 分离数据和视图状态(把数据层抽出来)

  • 避免级联更新带来的级联影响(M与V之间互相影响,数据流不清楚)

作用:

  • 提升数据一致性

  • 易于精确定位bug

  • 便于单元测试

三.结构

产生action               传递action           update state
view交互 -----------> dispatcher -----------> stores --------------> views

其中 dispatcher 全局只有一个, store 可以有多个。 dispatcher 只负责分发/传递 actionaction 到具体 state 变化之间的映射由 store 维护,所以 store 不是单纯的状态集 model ,还包含根据 action 更新 state 的逻辑。再往后就是 stateview 的联系,与数据绑定的具体实现有关,比如React里通过触发事件来通知更新(隐式 setState()

业务逻辑大多在 store 里,另一小部分交互相关的、异步操作相关的在 view (比如React组件)里

业务中经常有级联更新,比如交互操作把一条消息标为已读,要更新消息列表中该条消息的展示样式,还要把未读消息数量减一,级联更新让单向数据流变得不再清晰。Flux通过约束必须在顶层触发 action 来避免这种情况,一次 view 交互触发一组 action (把级联 action 打平,并把级联关系收在顶层,与交互操作直接相关)。而不是一次 view 交互触发一个大 action ,大 action 触发下面的级联 action

store 来完成控制反转, store 不提供 setXXX() 来允许外部影响内部 state ,唯一的方式是通过在 dispatcher 上注册的回调拿到外部数据,自己更新内部 state ,保持清楚的关注点分离

Flux

flux-simple-f8-diagram-explained

单dispatcher

中心枢纽,所有数据流都要过这里,有一张回调注册表,与各 store 建立联系。dispatcher本身只负责把 action 传递给 所有 store ,每个 storedispatcher 注册自己并提供一个回调, dispatcher 收到 action 后,所有已注册的 store 都将通过各自的回调拿到 action 及其携带的数据

应用规模较大的时候, dispatcher 会变得复杂一些,还要管理各 store 之间的 依赖关系 (按顺序调用各 store 注册的回调), store 可以通过显示声明等待其它 store 更新完成后再更新自己

一堆store

包含应用状态和逻辑,角色相当于 MVC里的重M ,但管理一堆 state ,而不像ORM里model代表一条数据记录,与Backbone里的 collection 也不同,只是简单地管理一组ORM风格的对象

一个 store 负责管理应用某块功能对应的内部状态,也就是说, store 不是按具体数据模型(ORM model),或者类型(Backbone collection)来分的,而是 按业务功能划分 。比如ImageStore负责记录一组图片的状态,TodoStore负责记录一组to-do item,这样, store 在数据上表示model集,在逻辑上表示一块单一功能

storedispatcher 上注册的回调接受一个 action 参数, store 里面是一个 switch 语句,根据 actiontype 分发给具体 state 更新方法, store 更新完毕后,通过广播事件来告诉 view 某些状态变了,对应的 view 取新的状态更新自己

一堆view

一些特殊的 view 监听来自自己依赖的 store 的广播事件,这些叫 view 叫controller-view,含有从 store 取数据及向下传递给后代 view 的逻辑,一个controller-view通常对应页面上的一块逻辑内容,像 view 的逻辑分组一样

controller-view接到来自 store 的事件后,先通过 store 暴露的 getter 取新数据,然后调用自己的 setState() 或者 forceUpdate() ,触发 render()render() 触发后代的 render()

通常把一大块 state 向下传递,下面各取所需,是为了减少需要管理的状态(不做细粒度状态切分)。相对于顶层controller从外部更新状态,这样能保持后代的功能尽量纯净

一堆action

一般用 工具 方法来包装 action 的生成、注册到 store 的过程,内部维持 storeaction 的联系(通过 actiontype

action 也可能来自别处,比如服务端,数据初始化时,服务返回错误码或者服务数据更新了,通过触发 action 来同步视图

四.特点

强制同步

action 分发/传递和 store 内部更新 state 都是同步的,异步操作的话,完成的时候手动触发 action ,整个机制不帮忙管理异步操作

让应用的信息流非常明确,bug场景对应的 state 向上追溯到 store ,到对应 action ,再到 view 层触发 action 的点,过程中所有环节都是同步的,那么 action 对应的 state 就是可预测的,不存在时序上的意外

控制反转(IoC)

store 自己内部更新 state ,而不是从外部更新,这样其它部分都不需要知道具体的 state 变化,状态变化只与 store 有关。而 store 只接收 action ,想对 store 做单元测试的话,只需要给一个初态,再丢过来一个 action ,然后看终态是否符合预期即可

语义化的action

store 要根据 action 更新 state ,这样一个 action 就相当于一组 state 更新操作的名字,有了语义含义, action 不知道怎样更新状态,但描述了预期结果,是相对稳定的(很少需要修改 action ,因为仅描述应用的某项功能),比如 MARK_THREAD_READ 希望把某条消息置为已读

额外的语义信息有利于追踪状态变化,通过调试工具就能让状态变化可追踪,比如Redux DevTools

没有级联action

不允许一个 action 触发另一个 action ,以避免级联更新带来的调试复杂度,所以 action 是“原子级”的,没有复杂的层级关系

五.约定

最佳实践 部分,也就是Flux的 道德约束

store

  • 缓存数据

  • 只暴露用来访问数据的 getter ,不给 setter

  • 对来自 dispatcher 的特定 action 作出响应

  • 任何数据变化时都触发change事件

  • 只在dispatch过程中才触发change事件

维护内部状态,且只在内部更新状态,关注特定 action ,数据变化时无理由触发change,其它时候不触发,除非是 dispatcher 引发的

action

  • 描述用户行为,而不是 setter (比如应该是 select-page 而不是 set-page-id

container

  • 用来控制 view 的React组件

  • 基本职能是收集来自 store 的信息,存到自己的 state

  • 不含 props 和UI逻辑

其实就是controller-view,与普通 view 的区别如上所述

view

  • 由container控制的React组件

  • 含有UI和渲染逻辑

  • 接收所有信息和回调作为props

普通的 view ,没什么特别的

参考资料


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

场景革命

场景革命

吴声 / 机械工业出版社 / 2015-7-1 / 59.00元

How-old如何引爆了朋友圈的全民脑洞狂欢? Uber是打车软件,还是入口? 为什么“自拍”会成为一个产业? 美团如何成为电影票房冠军的幕后推手? 商业进入了新物种时代,超级平台之后,PC时代以降,IoT(万物互联)崛起之时,到底什么是新的入口?一系列的颠覆使我们开始正视移动互联时代的品类创造方法,一场孕育已久的场景革命正在发生。 《场景革命:重构人与商业的连接》为......一起来看看 《场景革命》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换