Vuex
Vuex是什么?
Vuex是一个专为Vue.js开发的状态管理模式+库,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
最简单的Store
安装Vuex后,先创建一个store,仅需要提供一个初始state对象和一些mutation:
1 | // @/src/utils/store.js |
然后在main.js中使用它:
1 | import { createApp } from 'vue' |
现在可以通过 store.state 来获取状态对象,并通过 store.commit 方法触发状态变更:
1 | store.commit('increment') |
在组件中可以通过this.$store访问store:
1 | methods: { |
State
在Vue组件中获得Vuex状态
Vuex通过Vue的插件系统将store实例从根组件中注入到所有的子组件里。且子组件能通过this.$store访问到。
1 | const Counter = { |
mapState辅助函数
当一个组件需要获取多个状态时,将这些状态都声明为计算属性会显得冗余,我们可以使用mapState函数生成计算属性:
1 | import { mapState } from 'vuex' |
当要映射的计算属性与state的子节点名称相同时,我们可以给mapState传一个字符串数组:
1 | computed: mapState([ |
使用对象展开运算符,我们可以把mapState返回的对象与其他局部计算属性一起混用:
1 | computed: { |
Getter
Getter可以认为是store的计算属性。
Getter接受state为其第一个参数:
1 | const store = createStore({ |
通过属性访问
Getter会暴露为 store.getters 对象,可以以属性的形式访问这些值。
1 | store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }] |
可以在组件中使用Getter:
1 | computed: { |
通过方法访问
Getter可以返回一个函数来实现给Getter传参。
1 | getters: { |
1 | store.getters.getTodoById(2) |
mapGetters辅助函数
mapGetters 辅助函数仅仅是将store中的getter映射到局部计算属性:
1 | import { mapGetters } from 'vuex' |
如果想将一个getter属性另取一个名字,使用对象形式:
1 | ...mapGetters({ |
Mutation
更改Vuex的store中的状态的唯一方法是提交mutation。一个mutation有一个字符串的数据类型和一个回调函数,回调函数就是修改state的地方。mutation以state做为它的第一个参数:
1 | const store = createStore({ |
调用mutation时,要调用store.commit方法:
1 | // 将type写成字符串的写法,只会把第二个参数当成payload |
提交Payload
可以向store.commit传入额外的参数,即mutation的payload:
1 | mutations: { |
1 | store.commit('increment', 10) |
在组件中提交Mutation
可以在组件中使用 this.$store.commit('xxx') 提交mutation,或者使用 mapMutations辅助函数将组件中的methods映射为store.commit 调用。
1 | import { mapMutations } from 'vuex' |
Action
Action类似于mutation,不同在于Action提交的是mutation,并且Action可以包含异步操作。注册一个简单的Action:
1 | actions: { |
Action函数接受一个与store实例具有相同方法和属性的context对象,因此可以在action里通过context.commit提交一个mutation,或者通过context.state和context.getters来获取 state 和 getters。
可以使用ES6的参数解构来简化代码
1 | increment = ({ commit }) => { |
分发Action
Action通过store.dispatch触发:
1 | store.dispatch('increment') |
Action类似Mutation,支持同样的Payload方式和对象方式分发:
1 | // 以payload形式分发 |
在组件中分发Action
在组件中可以使用this.$store.dispatch分发action,或者使用mapActions将action映射到组件的methods中。
组合Action
store.dispatch可以处理被触发的action的处理函数返回的Promise,并且store.dispatch仍然返回Promise:
1 | actionA ({ commit }) { |
接下来可以链式调用:
1 | store.dispatch('actionA').then(() => { |
在另一个Action中也可以:
1 | actions: { |
结合async/await,可以优化结合action的代码:
1 | actions: { |
表单处理
在表单上对属于Vuex的store使用v-model会比较棘手:
1 | <input v-model="obj.message"> |
因为store的state只能通过触发mutation改变,直接通过v-model改变,会抛出错误。用常规的思维解决这个问题的方法是:给input表情绑定value,然后监听input或者change事件,在事件回调中触发mutation使事件改变。
这样做来修改数据太麻烦了,并且损失了v-model中很多方便的特性,下面是另一种修改的方法:在计算属性中提供set方法,然后再set方法中触发mutation:
1 | <input v-model="message"> |
1 | computed: { |