单向数据流的设计目的:任何UI不能直接对数据有写操作,就是防止同一份数据有多个地方同时在写。相对于直接进行双向绑定,编码稍微会复杂一点,但换来了排错和维护的便捷。
Flux 架构常用于 React 应用中,但它的核心理念也可以适用于 Vue.js 应用。比如 Vuex 就是一个借鉴于 Flux,但是专门为 Vue.js 所设计的状态管理方案。React 生态圈中最流行的 Flux 实现 Redux 也可以通过简单的绑定和 Vue 一起使用。
什么是Vuex
Vuex 是一个专门为 Vue.js 应用所设计的集中式状态管理架构。它借鉴了 Flux 和 Redux 的设计思想,但简化了概念,并且采用了一种为能更好发挥 Vue.js 数据响应机制而专门设计的实现。
为什么需要它?
当你的应用还很简单的时候,你多半并不需要 Vuex。也不建议过早地使用 Vuex。但如果你正在构建一个中型以上规模的 SPA,你很有可能已经需要思考应该如何更好地归纳 Vue 之外,应用的其他组成部分。这就是 Vuex 要大显身手的时刻。
我们在单独使用 Vue.js 的时候,通常会把状态储存在组件的内部。也就是说,每一个组件都拥有当前应用状态的一部分,整个应用的状态是分散在各个角落的。然而我们经常会需要把状态的一部分共享给多个组件。一个常见的解决策略为:使用定制的事件系统,让一个组件把一些状态“发送”到其他组件中。这种模式的问题在于,大型组件树中的事件流会很快变得非常繁杂,并且调试时很难去找出究竟哪错了。
为了更好的解决在大型应用中状态的共用问题,我们需要对组件的 组件本地状态(component local state) 和 应用层级状态(application level state) 进行区分。应用级的状态不属于任何特定的组件,但每一个组件仍然可以监视(Observe)其变化从而响应式地更新 DOM。通过汇总应用的状态管理于一处,我们就不必到处传递事件。因为任何牵扯到一个以上组件的逻辑,都应该写在这里。此外,这样做也能让我们更容易地记录并观察状态的变更(Mutation,原意为突变),甚至可以实现出华丽如时光旅行一般的调试效果。(译注:是时候安利一波 vue-devtools 了)
Vuex 也对如何管理分撒各地的状态增加了一些约束,但仍保留有足够面对真实使用场景的灵活性。
最简单的store
创建 Vuex store 的过程相当直截了当 - 只要提供一个初始化的 state 对象,以及一些 mutations:
import Vuex from 'vuex' const state = { count : 0 } const mutations = { INCREMENT (state){ state.count ++ } } export default new Vuex.Store({ state, mutations })
现在,你可以通过 store.state 来读取 state 对象,还可以通过 dispatch 某 mutation 的名字来触发这些状态变更:
store.dispatch('INCREMENT') console.log(store.state.count) // -> 1
如果你倾向于对象风格的分发方式,你可以用这种语法:
// 效果同上 store.dispatch({ type : 'INCREMENT' })
再次强调,我们通过分发 mutation 的方式,而非直接改变 store.state ,是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显,这样你在阅读代码的时候能更容易地解读应用内部的状态改变。此外,这样也让我们有机会去实现一些能记录每次状态改变,保存状态快照的调试工具。有了它,我们甚至可以实现如时间穿梭般的调试体验。
Vuex 使用 单一状态树 —— 是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个『唯一数据源(SSOT)』而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
以上只是一个用来展示 store 究竟是什么的一个极简例子。再谈谈三哥核心概念:State(状态),Mutations(变更) 和 Actions(动作)。
State和Getters
1.安装 Vuex 并且将您的根组件引入 store 实例:
import Vue from 'vue' import Vuex from 'vuex' import store from './store' import MyComponent from './MyComponent' // 关键点,教 Vue 组件如何处理与 Vuex 相关的选项 Vue.use(Vuex) var app = new Vue({ el : '#app', store, // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件 components : { MyComponent } })