Flux应用架构学习分析

今年FB的React在前端界受到了广泛的关注,广大码农纷纷投入到学习React的阵营中,我也不例外。React标榜自己只是个UI,并不是一个完整的MVC框架,所以一时出现了很多基于React的MVC框架,其中以fluxrefluxredux最为关注。笔者也没在实际项目中使用过React或者任何框架,所以只是想通过todomvc这个例子,浅显得分析下flux在项目中的来龙去脉,如果描述有误或者不正确的地方还望指出。

Flux介绍

flux主要包括四部分:

  • action:动作事件,可以理解为一个鼠标点击或者是键盘操作
  • dispatcher:分发者,接受到action后分配到各个store
  • store:数据和逻辑部分
  • views:视图页面,具有监听store功能的页面也称为controller-views


他们之间的联系可以用官网的上图来说明,呈单向数据流环状流程。现在看不懂这张图不要紧,我们可以先来看看代码,等看完todomvc这个demo应该能更好的理解这个图了。

views

整个demo主要划分为四个组件,一个是最外面红色部分的大容器,用来容纳其余的子组件。里面包含HeaderMainSectionFooter三个子组件,三个子组件内部又包含了更小粒度的子组件。如下图所示:

那先来看下TodoApp这个入口文件做了什么,初始状态获取了存在store中的数据,并把数据通过this.props的方式传递给子组件MainSection。等到render完组件后添加对store的事件监听,以及卸载组件后移除对store的监听。所以这个位于最顶层的view,也是一个controller-views。

action

接下来看下三个子组件的内部做了什么,除了加载各自内部子组件及数据传递外,我们可以看到凡是涉及到鼠标或者键盘操作的地方,都去调用了TodoAction中的方法。在TodoAction中包含了所有的操作,包括新建、更新、切换及删除。所以这个TodoAction正是上面流程图中对应的Action Creators,他的作用主要是负责接收所有的事件,并且把action传递给分发者dispatcher

dispatcher

当dispatcher接收到action后包装成为一个payload,包括actionType值及其他业务数据,并且调用dispatch方法。在dispatcher内部主要包括四个方法:registerunregisterwaitFordispatchpayload的状态也可以分为四个状态:

  • 未开始:Dispatcher_isPending = false
  • 开始:Dispatcher_isPending = true
  • 分发中:Dispatcher_isDispatching = true
  • 结束分发:Dispatcher_isHandled = true

这里dispatch调用了通过register方法注册的callback函数。如果此时注册了多个store,dispatch会遍历所有的callback函数,直到找到目标为止,数据一多有些资源浪费。

store

在这个demo中,入口文件TodoApp主动调用了TodoStore中的register方法,主要是用来注册dispatcher的回调函数。回调函数接收到从action传过来的数据后,通过switch方法来匹配到具体的业务操作中去。需要注意的一点是,这里store会收到所有action的通知,只能通过类型判断,来匹配自己所需要的。等做完操作后,store必须emit一个事件出来,因为前面提到的,最顶层的controller-views已经添加了对store的监听用来更新state,只有这样数据更新后才能体现到页面上来。这样再回过头去上面那张流程图,是不是觉得很清晰了呢。

小结

我们可以把flux整个流程归结为以下几点:

  • View 告知 Action Creator 准备一个 action
  • Action Creator 做好 action 并将其发送给 Dispatcher
  • Dispatcher 按照顺序将 action 传递给 store。每一个 store 都会受到所有的 action 通知,然后自行觉得是否对这个 action 做出响应,更新 state
  • 一旦 store 更新 state 完毕,就会告知订阅了该 store 的 controller view
  • 这些 controller view 就会向 store 请求更新了的 state
  • 从 store 中获得 state 之后,view controller 将会让它所管辖的子 view 渲染新的 state

flux其实就是一个订阅发布模式,但与传统的pub/sub模式区别在于,flux的每一个store都会收到所有action的通知,需要通过一个type值来过滤响应,然后emit一个事件,让controller view来监听更新view。因为存在每个store都会收到所有action的通知,也让flux成为很多人吐槽的地方,所以有人开始重新造轮子了,去掉了dispatcher这层,让action和store自带了pub/sub功能,对于使用者来说代码更为简洁了。后面我将来介绍下reflux和redux是怎么实现这个过程的。

参考

http://zhuanlan.zhihu.com/FrontendMagazine/20263396