Vuex
状态管理模式
集中式存储管理应用的所有组件的状态,以相应的规则保证状态以一种可以预测的方式发生变化。
容器 store
仓库包含应用中大部分状态。
- 响应式存储,组件从 store 中读取状态时,若store 中的状态发生变化,相应组件也会相应得到高效刷新;
- 不能直接改变 store 中的状态。唯一途径就是显示提交 mutation -> 可以方便跟踪每一个状态的变化。
创建 store,仅需提供初始 state 对象和一些 mutation:
// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
通过 store.state 来获取状态对象,通过 store.commit 方法触发状态变更:
store.commit('increment')
console.log(store.state.count) // -> 1
核心概念
-
State
单一状态树。Store 仓库中的 数据 状态 state。
// module1.js
const state = {
count: 0,
firstName: 'Kofe',
lastName: 'Chen'
}
-
Getter
Store 的 计算属性,其返回值会根据它的依赖被缓存起来,只有依赖值发生改变才会重新计算。
// module1.js
const getters = {
// 直接抛出其值
count: state => state.count,
// 根据依赖
fullName: state => state.firstName + ' ' + state.lastName
}
-
Mutation
更改 Vuex 的 store 中状态的唯一 方法 是提交 mutation (类似事件),每个 mutation 都有一个字符串的事件类型(type)和一个回调函数(handler)。
回调函数就是实际进行状态更改的地方,且会接受 state 作为第一个参数。
// module1.js
const mutations = {
increment(state) {
state.count ++
},
modifyFirstName(state, newName) {
state.firstName = newName
},
modifyLastName(state, newName) {
state.lastName = newName
}
}
-
Action
类似 mutation,Action 提交的是 mutation,但不是直接变更状态。Action 可以包含任意 异步操作。
// module1.js
const actions = {
// 第一个参数是默认的 { commit }
changeFullName({ commit }, { firstName, lastName }) {
// 假定 getName 方法返回 promise 对象
// 并且提交 firstName 和 lastName ,如果修改成功则提交 mutation
return getName({ firstName, lastName }).then(res => {
commit('modifyFirstName', res.firstName)
commit('modifyLastName', res.lastName)
})
},
// 与上面的写法相同,返回的仍然是 promise 对象
async changeFullName({ commit }, { firstName, lastName }) {
let res = await getName({ firstName, lastName })
commit('modifyFirstName', res.firstName)
commit('modifyLastName', res.lastName)
// 这里返回调用的时候想得到 then 里面的数据
return res
}
}
- Module
Vuex 允许将 store 分割成 module,每个模块拥有自己的 state、mutation、action、getter或甚至是嵌套子模块。数据量大复杂可以拆分成不同模块。
// index.js
import module1 from './modules/module1'
import module2 from './modules/module2'
// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
module1,
module2
}
})
示例代码文件格式
| -- store
index.js
| -- modules
| -- module1.js
| -- module2.js
module1.js 补充代码
export default {
state,
getters,
mutations,
actions
}
使用
main.js 中引入 store:
// ...省略
import store from './store'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
组件中使用:
<template>
<div>{{fullName}}</div>
<input v-model="firstName" placeholder="firstName">
<input v-model="lastName" placeholder="lastName" >
<a href="#" @click="onChange">改变全名</a>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
export default {
data() {
return {
firstName: '',
lastName: ''
}
},
computed: {
...mapGetters([
'count',
'fullName'
])
},
methods: {
...mapActions([
'changeFullName'
]),
onChange() {
this.changeFullName({ firstName: this.firstName, lastName: this.lastName })
.then(() => {
// ...
})
}
}
}
</script>