基本概念
1. github地址:GitHub - vuejs/vuex: 🗃️ Centralized State Management for Vue.js.
2. 官网地址:Vuex 是什么? | Vuex
3. Vuex理解
- 一个专为 Vue.js 应用程序开发的状态管理模式。
- 对 vue 应用中多个组件的共享状态进行集中式的管理(读/写)
4. 状态自管理应用
- state:驱动应用的数据源,存储的一些状态对象
- view:以声明方式将 state 映射到视图
- actions:操作状态对象的函数,响应在 view 上的用户输入导致的状态变化。
5. 多组件共享状态的问题
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
6. 之前的解决办法:数据传递
- 将数据以及操作数据的行为都定义在父组件
- 将数据以及操作数据的行为传递给需要的各个子组件(有可能需要多级传递)
7. 现在的解决办法:Vuex
- 对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
- 对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。
- Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
- 把组件的共享状态抽取出来,以一个全局单例模式管理,在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
- 通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
8. 简单示例
//vuex最核心的管理对象store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//相当于data对象的状态对象
const state = {
count: 0 // 指定初始化数据
}
//包含了n个直接更新状态的方法的对象
const mutations = {
INCREMENT (state) {
state.count++
},
DECREMENT (state) {
state.count--
}
}
//包含了n个间接更新状态的方法的对象
const actions = {
increment ({commit}) {
// 提交一个mutation请求
commit('INCREMENT')
},
decrement ({commit}) {
// 提交一个mutation请求
commit('DECREMENT')
},
incrementIfOdd ({commit, state}) {
if(state.count%2===1) {
// 提交一个mutation请求
commit('INCREMENT')
}
},
incrementAsync ({commit}) {
//在action中可以直接执行异步代码
setTimeout(() => {
// 提交一个mutation请求
commit('INCREMENT')
}, 1000)
},
}
//包含多个getter计算属性的对象
const getters = {
evenOrOdd (state) { // 当读取属性值时自动调用并返回属性值
return state.count%2===0 ? '偶数' : '奇数'
}
}
export default new Vuex.Store({
state,//状态对象
mutations,//包含多个更新state函数的对象
actions,//包含多个对应事件回调函数的对象
getters//包含多个getter计算属性函数的对象
})
9. import store from './store'之后,this对象中会自动加入$store用来获取vuex的信息
State
1. vuex中管理状态的对象
2. 状态定义与获取
//定义
const state = {
xxx: initValue
}
//获取
this.$store.state.xxx
3. 辅助函数:mapState
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// 对象方式的写法
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
//数组方式的写法
//当映射的计算属性的名称与 state 的子节点名称相同时
//可以给 mapState 传一个字符串数组
computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])
}
4. 如何将辅助函数与局部属性混合使用?
- ...三个点叫做对象展开运算符
computed: {
localComputed () { /* ... */ },
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
Getters
1. “getter”(可以认为是 store 的计算属性)
- getter 的返回值会根据它的依赖被缓存起来
- 且只有当它的依赖值发生了改变才会被重新计算。
- getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。
2. 计算属性定义与获取
//定义
const getters = {
//接受 state 作为其第一个参数
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
//可以接受其他 getter 作为第二个参数
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
},
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
//通过属性访问获取
this.$store.getters.doneTodos
//通过方法访问获取
this.$store.getters.getTodoById(2)
3. mapGetters
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
]),
//将一个 getter 属性另取一个名字,使用对象形式
...mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
}