Vuex 介绍
首先来一段通俗易懂的官方介绍。Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
快速入门
store
Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。一个基本的store由state(状态),getters(计算属性),mutations(状态改变),actions(行为)构成,就像下面这样创建一个基础的store:
store.js
import Vue from 'vue'
// 注册vuex
import Vuex from 'vuex'
Vue.use(Vuex)
// 根状态对象
// 每个vuex实例就是一个单例的状态树
const state = {
count: 0
}
// mutations 是一些真正能改变state的操作.
// 每一个 mutation 获取完整的状态树作为第一个参数(即state)
// 紧接着是另外一些关键的业务参数
// mutations 必须是同步函数才能被debugger 插件记录
const mutations = {
increment (state) {
state.count++
},
decrement (state) {
state.count--
}
}
// actions 是一些可以触发 mutations 的方法
// 异步操作.
const actions = {
increment: ({ commit }) => commit('increment'),
decrement: ({ commit }) => commit('decrement'),
incrementIfOdd ({ commit, state }) {
if ((state.count + 1) % 2 === 0) {
commit('increment')
}
},
incrementAsync ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('increment')
resolve()
}, 1000)
})
}
}
// getters 是一些根据state计算出新属性值的方法
const getters = {
evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
}
// 一个 Vuex的实例通过组合这些state,mutations, actions 和 getters 创建
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
vue组件中使用store
Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex))
import 'babel-polyfill'
import Vue from 'vue'
import Counter from './Counter.vue'
import store from './store'
new Vue({
el: '#app',
store,
render: h => h(Counter)
})
通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。
state
computed: {
count: function () {
return this.$store.state.count
}
}
mapState 辅助函数
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性:
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 方法定义在mapState对象上,使用箭头函数this指向mapState
//使用常规函数使其只向运行时对象,即组件本身
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。
computed: mapState([
// 映射 this.count 为 this.$store.state.count
'count'
])
对象展开运算符(... 位于对象前,包含在父对象中,将子对象的属性及赋值拆分赋值给父对象)
使用对象展开运算符,将mapstate和自定义局部计算属性混合使用:
computed: {
localComputed () { /* ... */ },
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
注:states如果和data结合,只能作为data数据的初始化使用,states中的状态改变无法同步展示到data的值数据上
Getter
getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。Getter 接受 state 作为其第一个参数, 接收getters作为第二个参数:
const getters = {
evenOrOdd: (state, getters) => state.count % 2 === 0 ? 'even' : 'odd'
}
通过属性访问:
Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:
this.$store.getters.evenOrOdd
通过方法访问(getter 传参):
你也可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用
getters: {
// ...
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
store.getters.getTodoById(2)
注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。
mapGetters 辅助函数
mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})