状态
单一状态树
Vuex 使用 **单一状态树** - 也就是说,这个单一对象包含了所有应用程序级别的状态,并充当“唯一的事实来源”。这也意味着通常每个应用程序只有一个 store。单一状态树使定位特定状态变得简单,并允许我们轻松地为调试目的获取当前应用程序状态的快照。
单一状态树并不与模块化冲突 - 在后面的章节中,我们将讨论如何将状态和 mutation 拆分为子模块。
您在 Vuex 中存储的数据遵循与 Vue 实例中的 data
相同的规则,即状态对象必须是纯对象。**另请参阅:** Vue#data.
将 Vuex 状态获取到 Vue 组件中
那么,我们如何在 Vue 组件中显示 store 中的状态呢?由于 Vuex store 是响应式的,因此从 store 中“检索”状态的最简单方法是在 计算属性 中返回一些 store 状态。
// let's create a Counter component
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
每当 store.state.count
发生变化时,它都会导致计算属性重新计算,并触发相关的 DOM 更新。
但是,这种模式会导致组件依赖于全局 store 单例。在使用模块系统时,它需要在使用 store 状态的每个组件中导入 store,并且还需要在测试组件时进行模拟。
Vuex 通过 Vue 的插件系统将 store “注入”到从根组件到所有子组件中,并且将在这些组件上以 this.$store
的形式可用。让我们更新我们的 Counter
实现
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
mapState 辅助函数
当组件需要使用多个 store 状态属性或 getter 时,声明所有这些计算属性可能会变得重复且冗长。为了解决这个问题,我们可以使用 mapState
辅助函数,它为我们生成计算 getter 函数,从而节省了一些按键操作。
// in full builds helpers are exposed as Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// arrow functions can make the code very succinct!
count: state => state.count,
// passing the string value 'count' is same as `state => state.count`
countAlias: 'count',
// to access local state with `this`, a normal function must be used
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
当映射的计算属性的名称与状态子树的名称相同时,我们也可以将字符串数组传递给 mapState
。
computed: mapState([
// map this.count to store.state.count
'count'
])
对象展开运算符
请注意,mapState
返回一个对象。我们如何将它与其他局部计算属性结合使用?通常,我们需要使用一个实用程序将多个对象合并为一个,以便我们可以将最终对象传递给 computed
。但是,使用 对象展开运算符,我们可以大大简化语法。
computed: {
localComputed () { /* ... */ },
// mix this into the outer object with the object spread operator
...mapState({
// ...
})
}
组件仍然可以拥有局部状态
使用 Vuex 并不意味着您应该将 **所有** 状态都放入 Vuex 中。虽然将更多状态放入 Vuex 会使您的状态 mutation 更明确且可调试,但有时它也会使代码更冗长且间接。如果某个状态严格属于单个组件,那么将其保留为局部状态可能就足够了。您应该权衡利弊,并做出适合您的应用程序开发需求的决定。