vuex 是一个存数据的容器,在全局都可以访问,用于解决跨多层/多个组件之间的数据交互问题。注意!本文为个人备忘,是 vuex 官方教程 的学习总结,通过阅读本文来学习 vuex 可能会产生疑惑。主要内容如下:
- 注册 vuex
- 概念 state - 数据的存放场所
- 概念 getters - 数据的 get 访问器
- 概念 mutations - 数据的同步 set 访问器
- 概念 actions - 数据的异步 set 访问器
注册 vuex
安装
yarn add vuex
注册
import Vuex from 'vuex'
Vue.use(Vuex)
新建
// 新建 store
const store = new Vuex.Store({
state: {
count: 0
}
})
// 绑定到 vue 实例中
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
状态 state
vuex 将保存在自己内部的数据称为 状态,所有的操作都是围绕着处理”状态“进行的。vuex 为了节省代码量和高效的在计算属性中使用 vuex 而设计了mapSatate
方法,详情见 这里。
新建
const store = new Vuex.Store({
// vuex 将状态保存在 state 对象里
state: {
count: 0
}
})
使用
// 组件内部的计算属性
computed: {
count() {
// 使用 $store 获取全局的 vuex 容器
return this.$store.state.count
}
},
访问器 getters
vuex 支持给状态设置 get 访问器,要写在 store
的 getters
属性里,用于访问状态时执行额外逻辑,可以在此封装常用方法,例如筛选或统计数量等。有两种使用方式,分别是带参数访问和不带参数访问。
不带参数访问
用于获取一些通用属性,例如获取状态长度等。访问器接受两个参数,参数1为该模块的状态state
,第二个参数为该模块的所有访问器getters
,可以通过第二个参数来使用其他getter
。注意,该方法在使用时不能在后面加()
,不然会报错。
// 定义
const store = new Vuex.Store({
state: {
todoList: [
{id: 1, text: '第一条', done: true},
{id: 2, text: '第二条', done: false},
]
},
getters: {
getDoneTodo: (state, getters) => {
return state.todoList.filter(todo => todo.done)
}
}
})
// 组件中调用
computed: {
count() {
// 直接使用访问器的名称
return this.$store.getters.getDoneTodo
// 这种会报错
// return this.$store.getters.getDoneTodo()
}
},
带参数访问
可以给访问器传递参数来进行查询,想要支持携带参数需要让 getter
返回一个方法:
// 定义
const store = new Vuex.Store({
state: {
todoList: [
{id: 1, text: '第一条', done: true},
{id: 2, text: '第二条', done: false},
]
},
getters: {
// 根据 id 查询数据
getTodo: state => id => {
return state.todoList.find(todo => todo.id === id)
}
}
})
// 组件中调用
computed: {
count() {
return this.$store.getters.getTodo(2)
}
}
同步setter访问器 mutations
mutations
是用于修改 state
的唯一手段,且其中只允许出现同步事务,因为无法追踪其状态,mutations
非常类似于事件,就连使用方法也和使用 $emit
发射事件很像。注意,mutations
,提交的修改也是响应式的,所以需要遵守 vue 的响应式原则,例如 修改对象的一个属性不会触发响应,应使用 Vue.set()。
mutations
接受两个参数,第一个参数是本模块的状态 state
,第二个参数则是 mutations
在调用时接受的参数。store.commit
方法也接受两个参数,第一个参数为访问器的名称,第二个参数为要传递的参数。commit()
也支持对象风格的提交方式,详情见 这里。
// 定义
const store = new Vuex.Store({
state: {
count: 0,
},
mutations: {
// 将 count 加指定的值,increment 是自定义的访问器名称
increment(state, payload) {
state.count += payload.value
}
}
})
// 组件中调用
methods: {
add() {
// 使用 commit 方法”发射事件“,并传递参数
this.$store.commit('increment', {
value: 10
})
}
},
如果觉得用store.commit
方法不够直观的话,vuex 提供了 mapMutations
方法来优化你的代码可读性
import { mapMutations } from 'vuex'
methods: {
// 映射指定访问器,以便可以直接用 this.increment 访问
...mapMutations([ 'increment' ]),
// 映射指定访问器,以便可以直接用 this.addNum 访问
...mapMutations({ addNum: 'increment' }),
add() {
// 这种写法
this.increment({
value: 10
})
// 等同于
// this.$store.commit('increment', {
// value: 10
// })
}
}
异步set访问器 actions
actions
的写法几乎和上一节的 mutations
完全一样,而且也包含一个 mapActions
,用法和上一节的 mapMutations
一样。而其区别有以下三点:
- 注册
action
时接受的第一个参数为context
对象,这个玩意跟整个store
实例很像,不过他是当前模块的 "store"。 -
actions
通过store.dispatch
方法触发,而不是store.commit
,不过他们俩的具体用法是一样的。 -
actions
里可以包含异步操作,但是最终还是要通过使用store.commit
来修改状态的。
// 定义
const store = new Vuex.Store({
state: {
count: 0,
},
// actions 最终还是要靠 mutations 修改数据
mutations: {
increment(state, payload) {
state.count += payload.value
}
},
actions: {
// actions 里方法可以跟 mutations 同名
// 因为第一个参数是整个 "store",所以可以通过解构取出其中的 commit 方法
increment({ commit }, payload) {
setTimeout(() => {
commit('increment', payload)
}, 1000)
}
}
})
// 组件中调用
methods: {
add() {
this.$store.dispatch('increment', {
value: 10
})
}
},
可以在 action
里返回一个 Promise
来使得调用者继续处理:
// 定义
actions: {
increment({ commit }, payload) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('increment', payload)
resolve()
}, 1000)
})
}
}
// 调用
this.$store.dispatch('increment', {
value: 10
}).then(() => {
...
})