有关状态管理这个词儿已经出现好几年了。不过实际中大多数项目其实还用不上状态管理,并且即便在项目中用上,但也用得并很差,尤为是初学者,更多的是去记录各类API的用法,殊不知其核心思想,很难快速实现状态管理的最佳实践。javascript
以前在 Vue组件通讯事件总结 这篇文章里研究过Vue里面各个组件之间的数据通讯,通常页面不是特别复杂的项目,使用这篇文章总结的通讯方式足够了,但当前端页面复杂度愈来愈高,props
、$emit
、$listeners
、ref / refs
、eventBus
这些方法也许还不够方便,这个时候能够开始尝试vuex的状态管理机制了。前端
用一个通俗易懂的概念来解释状态管理:全局变量。vue
可是在项目的开发中,咱们应该都记得前辈的叮嘱:尽可能不要或少用全局变量,由于那是不可控的操做,任意的操做均可能致使数据的改变,形成全局污染,没法追踪数据变化过程,因此开发中咱们小菜鸟也大都避免去过多的操做全局变量。java
但当项目复杂度比较高时,也许多个组件、多个页面之间须要实现一种数据或状态的共享,这时候,咱们就能够将这些状态统一的进行管理,既能够实现共享状态,又能追踪到数据的变化,可能这也是状态管理诞生的一种缘由吧。vuex
固然,跟全局变量同样,各个文章里面也是叮而嘱之,若是没有哦必要,尽可能不要使用状态管理。编程
关于如何在UI试图中合理地修改state,Facebook提出了flux思想。redux
Flux 是一种架构思想,专门解决软件的结构问题。后来的rudux和vux也都是由Flux的思想演化出来的。数据结构
Flux将一个应用分红四个部分: View(视图)、Action(动做)、Dispatcher(派发)、Store(数据)架构
总体流程:框架
这是一个单向流动的过程,
用户访问view -> 触发事件action -> Dispatcher知道后告知store要更新 -> store更新,触发视图View更新页面
特色:
redux的核心概念:
Redux store 是单一数据源,且store是不可变的,Redux 没有 dispatcher 的概念,
特色:
store.dispatch()
是 View 发出 Action 的惟一途径Store 中提供了几个管理 state
的 API:
store.getState()
:获取当前 statestore.dispatch(action)
:触发 state
改变(惟一途径)store.subscribe(listener)
:设置 state
变化的监听函数(若把视图更新函数做为 listener 传入,则可触发视图自动渲染)总体流程:
Action Creator -> 触发action -> store.dispatch(action) -> reducer(state, action) -> 更新state
MobX 是经过透明的函数响应式编程使得状态管理变得简单和可扩展,是一个用法简单优雅、同时具备可扩展性的状态管理库。
和 Redux 对单向数据流的严格规范不一样,Mobx 只专一于从 store 到 view 的过程。在 Redux 中,数据的变动须要监听,而 Mobx 的数据依赖是基于运行时的,这点和 Vuex 更为接近。
若是你们使用过 Vue 的话相信对其双向绑定 MVVM 的思想并不陌生,React + Mobx 至关因而 Vue 全局做用域下的双向绑定,而 Vue 的状态管理框架 Vuex 倒是借鉴了 Flux 架构,连尤大都说,彷佛有点你中有我,我中有你的关系。
特色:
仍然放一张vuex的示意图:
vuex的运做原理跟redux稍有不一样。由于Vue虽然是单向数据流,但Vue 基于 ES5 中的 getter/setter 来实现视图和数据的双向绑定,所以 Vuex 中 state 的变动能够经过 setter 通知到视图中对应的指令来实现视图更新。且state不是经过actions来修改的,而是经过mutations。
特色:
单向数据流, 经过 store.dispatch()
调用 Action ,在 Action 执行完异步操做以后经过 store.commit()
调用 Mutation 更新 State
单一数据源
actions 能够是 异步操做,故可在action中调用后台接口获取新的数据;
mutations 只能是 同步操做;
mutations 和 actions 均可直接更改 state,可是当 action 含有异步操做时,会使得数据变化混乱,难以跟踪,使得调试困难;基于以上缘由,Vuex 规定只能是 mutations 来改变 state。
总体流程:
用户访问view -> 触发事件action ->action中触发对应的mutation -> 在mutation函数中改变state -> 经过 getter/setter 实现的双向绑定的机制,视图View会自动更新页面
使用一句话总结:commit mutation,dispatch action
从上面几种热门的状态管理实现方式来看,能够发现,这几种数据流模型几乎都是从 action 到 view 之间的一种数据流动,总的过程能够大体简化为:
action -> 更新 state(视图层)
一、 数据状态中心: state和store
能够发现,在redux和flux中,数据状态用store表示,而在vuex和mobx中,这个store被state替代。
和 Redux 中使用不可变数据来表示 state 不一样,Vuex 中没有 reducer 来生成全新的 state 来替换旧的 state,Vuex 中的 state 是能够被修改的。
Vuex 中的 state 是可修改的,而修改 state 的方式不是经过 actions,而是经过 mutations。更改 Vuex 的 store 中的状态的惟一方法是提交 mutation。
二、 行为action
咱们想要更新视图内容,第一步就是要有触发的动做,action就是向store发起更新请求的最小单元。但action并不是是一个动词,它是一个行为的描述,本质上是一个纯声明式的数据结构,仅提供对事件的描述,不提供事件的具体逻辑
在rudux中,生成action有两种方式:
声明对象:
const action = {
type: 'ADD_TODO',
text: '生成一个action'
}
dispatch(action)
复制代码
函数生成:
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
dispatch(addTodo())
复制代码
三、dispatch
在各种应用状态管理的模型中,一般都会有一个dispatch
方法,它就声明在Store
上,负责调用各个Action
,而后由Store
上对应的分发机制进行处理。
四、Reducer / Mutation
如今到了咱们的第三步,更新状态。flux和mobx对状态更新的处理是直接更改,而redux和vuex中间还会多出一个reducer和mutation来处理更新的工做。
至于reducer和mutation,分别是针对redux和vuex的不一样工做机制。
先看reducer,Actions
只能描述发生了什么,并不能描述状态发生了什么变化,Reducers
指定 state tree
将要发生什么,它主要的工做内容是:接受一个action,而后经过switch匹配action的type,做出相应的处理后,返回一个新的对象。为何是新的对象呢?由于redux最核心的一个概念,store是不可变的, Redux 是一个实践函数式编程(FP)理念的库。下面是一个最简单的reducer:
const items = (state = [], action) => {
switch (action.type) {
case "ADD_ITEM":
return [...state, { text: action.text }]
default:
return state
}
}
复制代码
再来看mutation,一个 mutation 是由一个 type 和与其对应的 handler 构成的,type 是一个字符串类型用以做为 key 去识别具体的某个 mutation,handler 则是对 state 实际进行变动的函数。
// store
const store = {
books: []
}
// mutations
const mutations = {
[ADD_BOOKS](state, book) {
state.books.push(book)
}
}
复制代码