在目前前端的组件化开发风潮中,无论是 PC 端还是移动端,对于组件化来讲有一个非常重要的就是状态管理。要理解什么状态管理,首先就要理解什么是状态。
实际上,状态的概念非常简单,就是每个组件自身可以维护一些数据。而由于组件与组件之间存在一些关系(例如父子关系、兄弟关系),这就避免不了组件之间要进行数据的传递,这也就是所谓的组件状态管理出现的背景。

如果使用传统的 porps 或者自定义事件的形式来传递组件的数据,就会显得非常的繁琐,一个组件状态更新,需要一层一层传递到根组件,再由根组件一层一层往下传递。这样一个应用的组件层数嵌套得越深,工作量就会变得越大。
在这样的背景下,专门用于状态管理的库就出现了。

状态管理库的核心思想很简单,专门拿一个 store 的仓库来管理所有组件的状态,假如一个组件状态更新后,同步更新仓库中的状态,这样另一个组件再获取最新的状态时,也不用向之前那样层层传递,直接从仓库获取最近的状态即可。
目前,市面上比较流行的状态管理库有:
- Flux
- Vuex
- Redux
- Mobx
Flux#
2013 年,Facebook 亮出 React 的时候,也跟着带出了 Flux。Facebook 认为两者相辅相成,结合在一起才能构建大型的 JavaScript 应用。
Flux 的组成:
- View: 视图层
- Action: 动作,即数据改变的消息对象(可通过事件触发、测试用例触发等)
- Store 的改变只能通过 Action
- 具体 Action 的处理逻辑一般放在 Store 里
- Action 对象包含 type(类型)与 payload(传递参数)
- Action 仅仅是改变 Store 的一个动作,一般包含该动作的类型、传递的数据
- Dispatcher: 派发器,接收 Actions,发给所有的 Store。
- Store: 数据层,存放应用状态与更新状态的方法,一旦发生变动,就提醒 Views 更新页面

Flux 的特点:
- 单向数据流。视图事件或者外部测试用例发出 Action,经由 Dispatcher 派发给 Store,Store 会触发相应的方法更新数据、更新视图
- Store 可以有多个
- Store 不仅存放数据,还封装了处理数据的方法
Vuex#
Vuex 是 Vue 官方推出的状态管理库。
Vuex 的核心概念:
- Store: Vuex 采用单一状态树,每个应用仅有一个 Store 实例,在该实例下包含了 state、actions、mutations、getters、modules。
- State: Vuex 为单一数据源。可以通过 mapState 辅助函数将 state 作为计算属性访问,或者将通过 Store 将 state 注入全局之后使用 this.$store.state 访问。State 更新视图是通过 vue 的双向绑定机制实现的。
- Getter: Getter 的作用与 filters 有一些相似,可以将 State 进行过滤后输出。
- Mutation: Mutaion 是 vuex 中改变 State 的唯一途径(严格模式下),并且只能是同步操作。Vuex 中通过 store.commit( ) 调用 Mutation。
- Action: 一些对 State 的异步操作可以放在 Action 中,并通过在 Action 提交 Mutaion 变更状态。Action 通过 store.dispatch( ) 方法触发。可以通过 mapActions 辅助函数将 vue 组件的 methods 映射成 store.dispatch 调用(需要先在根节点注入 store)。
- Module: 当 Store 对象过于庞大时,可根据具体的业务需求分为多个 Module,每个 Module 都具有自己的 state 、mutation 、action 、getter。
Vuex 的特点:
- 单向数据流。View 通过 store.dispatch( ) 调用 Action,在 Action 执行完异步操作之后通过 store.commit( ) 调用 Mutation 更新 State,通过 vue 的响应式机制进行视图更新。
- 单一数据源,和 Redux 一样全局只有一个 Store 实例。
- 可直接对 State 进行修改。
Redux#
作为一款针对 JavaScript 应用的可预测状态管理容器库,由 Dan Abramov 在 2015 年创建的 Redux 在创建之初曾受到 Flux 架构以及函数式 Elm 的启发。后来,随着 Dan Abramov 加盟 Facebook,Redux 最终成为 Facebook 旗下的一个子项目。Redux 之所以被广泛接受,是因为 Redux 融合了各家技术于一身,不但简化了 Flux 的流程与开发方式,还引入了一些优秀的设计理念。
作为一个应用状态管理库,Redux 和 Flux 有很多相似的地方。不同之处在于,Flux 可以有很多个改变应用状态的 Store,并可以通过事件来触发状态的变化,组件可以通过订阅这些事件来和当前状态保持同步。
在 Redux 中,则并没有 Dispatcher(分发器)的概念,Redux 使用一个单独的常量状态树来保存整个应用的状态,并且这个对象是不能直接被改变的。如果某些数据发生改变,那么就会创建出一个新的对象。
由于 Redux 是在 Flux 的基础上扩展出的一种单向数据流的实现,所以数据的流向、变化都能得到清晰的控制,并且能很好地划分业务逻辑和视图逻辑。
Redux 的组成:
- Store: 存储应用 state 以及用于触发 state 更新的 dispatch 方法等,整个应用仅有单一的 Store
- Store 中提供了几个 API:
- store.getState( ): 获取当前 state
- store.dispatch(action): 用于 View 发出 Action
- store.subscribe(listener): 设置监听函数,一旦 state 变化则执行该函数(若把视图更新函数作为 listener 传入,则可触发视图自动渲染)。
- Action: 同 Flux,Action 是用于更新 state 的消息对象,由 View 发出。有专门生成 Action 的 Action Creator
- Reducer: 是一个用于改变 state 的纯函数(对于相同的参数返回相同的返回结果,不修改参数,不依赖外部变量),即通过应用状态与 Action 推导出新的 state: (previousState, action) => newState。Reducer 返回一个新的 state

Redux 的特点:
- 单向数据流。View 发出 Action(store.dispatch(action)),Store 调用 Reducer 计算出新的 state,若 state 产生变化,则调用监听函数重新渲染 View (store.subscribe(render))。
- 单一数据源,只有一个 Store。
- state 是只读的,每次状态更新之后只能返回一个新的 state。
- 没有 Dispatcher,而是在 Store 中集成了 dispatch 方法,store.dispatch( ) 是 View 发出 Action 的唯一途径。
Mobx#
作为一个应用状态管理库,Redux 被广泛用于复杂的大型应用中,在很多大型 Web 前端应用中都可以看到它的身影。不过除了 Redux,社区里近年来还有另一产品呼声很高,那就是 Mobx。
MobX 是由 Mendix、Coinbase 和 Facebook 开源的状态管理框架。MobX 背后的哲学是:
任何源自应用状态的东西都应该自动地获得。
意思就是,当状态改变时,所有应用到状态的地方都会自动更新。它通过响应式函数编程来实现状态的存储和管理。受到面向对象编程和响应式编程的影响,Mobx 可以将状态包装成可观察对象,通过观察和修改对象的状态进而实现视图的更新。
这样一个功能强大,上手非常容易的状态管理工具。就连 Redux 的作者也曾经向大家推荐过它,在不少情况下你的确可以使用 Mobx 来替代掉 Redux。
MobX 的核心概念:
- State: 驱动应用的数据
- Computed values: 计算值。如果你想创建一个基于当前状态的值时,请使用 computed
- Reactions: 反应,当状态改变时自动发生
- Actions: 动作,用于改变 State
- 依赖收集(autoRun): MobX 中的数据以来基于观察者模式,通过 autoRun 方法添加观察者

MobX 的特点:
- 数据流流动不自然,只有用到的数据才会引发绑定,局部精确更新(细粒度控制)
- 没有时间回溯能力,因为数据只有一份引用
- 基于面向对象
- 往往是多个 Store
- 代码侵入性小
- 简单可扩展
- 大型项目使用 MobX 会使得代码难以维护
最后总结一下:
- Flux 、Redux 、Vuex 均为单向数据流。
- Redux 和 Vuex 是基于 Flux 的,Redux 较为泛用,Vuex 只能用于 vue。
- Flux 与 MobX 可以有多个 Store,Redux、Vuex 全局仅有一个 Store(单状态树)。
- Redux、Vuex 适用于大型项目的状态管理,MobX 在大型项目中应用会使代码可维护性变差。
- Redux 中引入了中间件,主要解决异步带来的副作用,可通过约定完成许多复杂工作。
- MobX 是状态管理库中代码侵入性最小的之一,具有细粒度控制、简单可扩展等优势,但是没有时间回溯能力,一般适合应用于中小型项目中。