一、介绍
Vuex是专为Vue.js应用程序开发的状态管理模式(state management pattern)。本文针对Vue2版本简单介绍如何配置Vuex3对项目进行项目管理。
简单理解为可以把多个组件共享的变量(状态)全部存储在一个对象里面,将该对象放在顶层的Vue实例中,让其他组件使用并响应式刷新。
如上图所示,Vuex主要包含Actions、Mutations、State,将在稍后详细介绍。Devtools是能够记录vuex中state修改记录的浏览器插件,可以在chrome插件商店中下载。
二、Vuex的初步使用
1.安装
sudo npm install vuex@3
2.在src目录下新建store文件夹,文件夹内添加index.js
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
const store = new Vuex.Store(
{
state:{
count:0
},
mutations:{
ADD(state){
state.count++
}
},
actions:{},
getters:{},
modules:{},
}
)
export default store
3.在main.js中给根实例引入并绑定store
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store,
}).$mount('#app')
三、Vuex核心概念
1.state
Vuex使用单一状态树,用一个对象包含全部应用层级的状态,这意味着每个Vue应用将仅仅包含一个store实例。我们可以在注入vuex的子组件中通过一下方式访问存储在state中的变量:
{{$store.state.count}}
2.Getter
在使用state中的属性时,我们往往需要使用属性的派生状态,如过滤等操作,getter可以认为是store中的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。getter接受state作为第一个参数,也可以接受getters作为第二个参数:
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
}
})
我们可以在组件中通过以下方式使用getter
this.$store.getters.doneTodosCount
getter 还可以返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。
getters: {
// ...
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
3.Mutations
更改Vuex中store的唯一方法是提交mutation。每格mutation都有一个字符串的事件类型(type)和一个回调函数(handler),这个回调函数就是进行state更改的地方,且接受state作为第一个参数。
const store = createStore({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})
当我们在组件中调用mutation时,可以在组件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations
辅助函数将组件中的 methods 映射为 store.commit
调用
普通提交:
store.commit('increment')
mapMutations提交:
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
store.commit可以传入额外的参数,即mutaion的载荷payload,payload通常是一个对象;
// ...
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit('increment', {
amount: 10
})
* mutation必须是同步函数,不然devtools将无法追踪vuex状态的改变
4.Action
Action类似于mutation,不同在于:
const store = createStore({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
setTimeout(()=>{
context.commit('increment')
},1000)
}
}
})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters,context对象并不是实例本身。
可以使用ES6语法来简写代码:
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
action通过store.dispatch方法触发,且同样支持载荷对象分发:
store.dispatch('increment')
// 以载荷形式分发
store.dispatch('incrementAsync', {
amount: 10
})
// 以对象形式分发
store.dispatch({
type: 'incrementAsync',
amount: 10
})
在组件中奋发actions(需在根结点注入$store):
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}
store.dispatch
可以处理被触发的 action 的处理函数返回的 Promise
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
store.dispatch('actionA').then(() => {
// ...
})
并且 store.dispatch
仍旧返回 Promise,所以可以将actions组合:
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
5. Module
由于使用单一状态树,应用的所有状态集中到一个对象中肯能会变的相当臃肿。module允许我们将store分割成模块,每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
const store = createStore({
state:{},
getters:{},
modules: {
//...
a:{
state:{},
getters:{},
},
b:{
state:{},
getters:{},
}
}
})
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象,模块内部的 getter,根节点状态会作为第三个参数暴露出来:
const moduleA = {
state: () => ({
count: 0
}),
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
对于模块内部的 action,局部状态通过 context.state
暴露出来,根节点状态则为 context.rootState
:
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}