用一个通俗易懂的概念来解释状态管理:全局变量。
但是在项目的开发中,我们应该都记得前辈的叮嘱:尽量不要或少用全局变量,因为那是不可控的操作,任意的操作都可能导致数据的改变,造成全局污染,无法追踪数据变化过程,所以开发中我们小菜鸟也大都避免去过多的操作全局变量。
但当项目复杂度比较高时,也许多个组件、多个页面之间需要实现一种数据或状态的共享,这时候,我们就可以将这些状态统一的进行管理,既可以实现共享状态,又能追踪到数据的变化,可能这也是状态管理诞生的一种原因吧。
当然,跟全局变量一样,各个文章里面也是叮而嘱之,如果没有哦必要,尽量不要使用状态管理。
关于如何在UI试图中合理地修改state,Facebook提出了flux思想。
Flux 是一种架构思想,专门解决软件的结构问题。后来的rudux和vux也都是由Flux的思想演化出来的。
Flux将一个应用分成四个部分: View(视图)、Action(动作)、Dispatcher(派发)、Store(数据)
这是一个单向流动的过程,
用户访问view -> 触发事件action -> Dispatcher知道后告知store要更新 -> store更新,触发视图View更新页面
redux的核心概念:
Redux store 是单一数据源,且store是 不可变 的, Redux 没有 dispatcher 的概念 ,
Store 中提供了几个管理 state 的 API:
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。
用户访问view -> 触发事件action ->action中触发对应的mutation -> 在mutation函数中改变state -> 通过 getter/setter 实现的双向绑定的机制,视图View会自动更新页面
使用一句话总结: commit mutation,dispatch action
从上面几种热门的状态管理实现方式来看,可以发现,这几种数据流模型几乎都是从 action 到 view 之间的一种数据流动,总的过程可以大致简化为:
1、 数据状态中心: 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。
2、 行为action
我们想要更新视图内容,第一步就是要有触发的动作,action就是向store发起更新请求的最小单元。但action并非是一个动词,它是一个行为的描述,本质上是 一个纯声明式的数据结构,仅提供对事件的描述,不提供事件的具体逻辑
在rudux中,生成action有两种方式:
3、dispatch
在各类应用状态管理的模型中,通常都会有一个 dispatch 方法,它就声明在 Store 上,负责调用各个 Action ,然后由 Store 上对应的分发机制进行处理。
4、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 实际进行变更的函数。
// storeconst store = { books: []}// mutationsconst mutations = { [ADD_BOOKS](state, book) { state.books.push(book) }}