前言
一般的,我们对数据进行管理是以下流程:
数据修改视图,视图上绑定了一些方法。接受到用户的响应后执行 action 控制对应的数据。但是这种单向数据流在遇到多个组件共享状态时易碎。
那么如何解决呢?
Vuex 实现了将组件的共享状态抽取出来,以一个全局单例模式管理。 实际上, Vuex 就是一个数据仓库,对象存储数据,数据可被组件共享。State
- Vuex 对象存储的数据,与 Vue 实例中的 data 遵循相同的规则
在 Vue 组件中获取 Vuex 数据
- 把 Vuex 的状态映射到当前组件的计算属性
- 执行代码我们可以看到 Counter 组件新增了一个计算属性,对应了 Vuex 中的 state 状态。
- 当 state 状态变化了,多个组件中的计算属性监控到了变化,执行设定的操作。即达到共享属性,同步变化。
// 注入 Vuex
Vue.use(Vuex)
// 创建一个 Vuex 对象
const store = new Vuex.Store({
state:{
count :0,
firstName:'chili',
lastName:'tom'
}
})
// 创建一个 Counter 组件
const Counter = {
template:`<div>{{ count }}</div>`,
computed:{
count(){
return this.$store.state.count
},
// ...Vuex.mapState(['firstName','lastName'])
}
}
const app = new Vue({
el:'#app',
store,
components:{ Counter },
template:`
<div class = "app">
<Counter/>
</div>
`
})
当 state 里的数据变多且都要一一映射,以上写法太麻烦,我们可以借助** mapState 辅助函数**来达到我们希望的效果。
mapState 返回的是一个数组对象,我们可以将最终对象传给 computed 属性
computed:{
<!-- count(){
return this.$store.state.count
},
firstName(){
return this.$store.state.firstName
},
lastName(){
return this.$store.state.lastName
}, -->
//等同于
...Vuex.mapState(['count','firstName','lastName'])
}
Getter
- 类似于组件中的计算属性,因此可以认为是 store 的计算属性
- 响应式依赖自动缓存
在 Vue 组件中获取 Vuex 中的 Getter
- 与 state 一样,都是获取查看数据,也会把 Vuex 的 Getter 映射到当前组件的计算属性
const store = new Vuex.Store({
state:{
count :0,
firstName:'chili',
lastName:'tom'
},
getter:{
fullName(state){
return state.firstName+' '+state.lastName
}
}
})
const counter = {
template:`
<div>
<div>{{ count }}</div>
<div>{{ firstName }} {{ lastName }}</div>
<div>{{ fullName }}</div>
</div>`,
computed:{
...Vuex.mapState(['count',firstName','lastName']),
fullName(){
return this.$store.getters.fullName
}
// ...Vuex.mapGetters(['fullName'])
}
}
mapGetters 辅助函数可将 store 中的 getter 映射到计算属性
Mutations (同步函数)
- 由于直接对修改数据是不可控的,因此可以提供某些方法对属性进行修改。
- 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
- 映射到组件中的 methods 中
会接受 state 作为第一个参数
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})
// 提交 mutation
store.commit('increment')
向 store.commit 传入额外的参数
mutations: {
increment (state, n) {
state.count += n
}
}
store.commit('increment', 2)
在组件中提交 Mutation
- 使用 this.$store.commit('xxx') 提交 mutation,
- 使用 mapMutations 辅助函数
Vue.use(Vuex)
const store = new Vuex.Store({
state:{
count :0,
},
mutations:{
increment(state){
state.count++
}
}
})
const counter = {
template:`
<div>
<div>{{ count }}</div>
<button @click="add">+</button>
</div>`,
methods:{
<!-- add(){
this.$store.commit('increment')
} -->
...mapMutations({
add: 'increment'
// 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
const app = new Vue({
el:'#app',
store,
components:{ counter },
template:`
<div class = "app">
<counter/>
</div>
`
})
Actions (异步操作)
- 类似与 mutation,都是修改状态
- Action 提交的是 mutation,而不是直接变更状态。
- 映射到组件中的 methods 中
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
在组件中分发 Action
- 使用 this.$store.dispatch('xxx')
- 使用 mapActions 辅助函数
Modules
- 把当前模块的 Vuex 对象进行拆分
- 代码模块化,具有逻辑性
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
参考文献:Vuex官网