Vuex 使用 单一状态数 ——用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。
单一状态数让我们能够直接地定位任一特定的状态片段,在调式的过程中也能轻易取得整个当前应用状态的快照。
单状态数跟模块化并不冲突——在后面的章节里我们会讨论如何将状态和状态变更事件分布到各个子模中。
存储在 Vuex 中的数据和Vue实例中的 data 遵循相同的规则,例如状态对象必须是纯粹的
在Vue 组件中获得Vuex状态
1. 单个组件使用
那么我们如何在Vue组件中展示状态呢?由于Vuex的状态存储时响应式的,从**store**实例中读取状态最简单的方法就是在 **计算属性** 中返回某个状态
// 创建一个 counter 组件
const counter = {
template:`<div>{{count}}</div>`,
computed:{
count(){
return store.state.count
}
}
}
每当 store.state.count 变化的时候,都会重新求取计算属性,并且触发更新相关联的DOM
然而,这种模式导致组件依赖全局状态单例。在模块化的构建系统中,在每个需要使用state的组件中需要频繁地导入,并且在测试组件时需要模拟状态。
2. 从根组件注册store
Vuex 通过 Store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex)):
const app = new Vue({
el:"#app",
store, //es6语法,属性跟值同名可缩写为一个
components:{Counter},
template:`
<div class="app">
<Counter></Counter>
</div>
`
})
通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。让我们更新下 Counter 的实现
const Counter = {
template:`<div>{{count}}</div>`
computed:{
count(){
this.$store.state.count
}
}
}
mapstate 辅助函数
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。
为了解决这个问题,我们可以使用 mapstate 辅助函数帮助我们生成计算属性,少安几次键呢!
import {mapState} from 'vuex' //引入 mapState
export default{
// ...
computed:mapState({
// 箭头函数可使代码更简练
count:state => state.count,
// 传字符串参数 'count' 等同于 'state => state.count'
countAlias:'count',
// 为了能够使用 this 获取局部状态,必须使用常规函数
countPlusLocalState(state){
return state.count + this.localCount
}
})
}
当映射的计算属性的名称与state 的子节点名称相同时,我们也可以给 mapState 传入一个字符串数组
computed:mapState(['count'])
对象展开运算符
mapState 函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?通常 ,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给 computed 属性。但是自从有了 对象展开运算符 ,我们可以极大地简化写法:
export default{
computed:{
localComputed(){ /* ... */},
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
}
组件仍然保有局部状态
使用 Vuex 并不意味着你需要将 所有的 状态放入 Vuex。虽然将所有的状态放到Vuex会使状态变化更显示和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是别作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。
注意:
- 在使用 store.state 对象里面的属性不要根本地组件的data函数返回对象的属性相同。相同则优先使用data函数返回对象的属性