Vuex
1、什么是Vuex
- 概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对于Vue应用中多个组件间的共享状态进行集中管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信
2、安装与配置vuex
2.1、安装
- 安装:npm install vuex / yarn add vuex
- 注意:vue2.x需安装vuex3版本,vue3.x需安装vuex4版本
2.2、配置
-
在src路径下创建store文件夹,然后创建index.js文件,文件内容如下:
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); // 定义值 const state = {}; // 修饰器 const getters = {}; // 修改值 const mutations = {}; // 异步修改值 const actions = {}; export default new Vuex.Store({ state, getters, mutations, actions, }); -
修改main.js:
import Vue from 'vue' import App from './App.vue' import store from './store'; // 引入我们前面导出的store对象 Vue.config.productionTip = false new Vue({ store, render: h => h(App), }).$mount('#app')- 组件中使用:
<template> <div></div> </template> <script> export default { mounted() { // 使用this.$store.state.XXX可以直接访问到仓库中的状态 console.log(this.$store.state.name); } } </script>
3、使用vuex
3.1、…mapState
-
官方建议我们以上操作this.$store.state.XXX最好放在计算属性中,当然,我也建议你这么使用,这样可以让你的代码看起来更优雅一些,就像这样:
export default { mounted() { console.log(this.getName); }, computed:{ getName() { return this.$store.state.name; } }, } -
是不是每次都写this.$store.state.XXX让你感到厌烦,你实在不想写这个东西怎么办,当然有解决方案,就像下面这样:
<script> import { mapState } from 'vuex'; // 从vuex中导入mapState export default { mounted() { console.log(this.name); }, computed: { ...mapState(['name']), // 经过解构后,自动就添加到了计算属性中,此时就可以直接像访问计算属性一样访问它 }, } </script> -
你甚至可以在解构的时候给它赋别名,取外号,就像这样:
...mapState({ aliasName: 'name' }), // 赋别名的话,这里接收对象,而不是数组
3.2、修饰器:Getter
-
什么是修饰器?以下假设一个场景:
- 设想一个场景,你已经将store中的name展示到页面上了,而且是很多页面都展示了,此时产品经理过来找事儿:
- 产品经理:所有的name前面都要加上“hello”!
这时候,你第一想到的是怎么加呢,emm…在每个页面上,使用this.$store.state.name获取到值之后,进行遍历,前面追加"hello"即可。
错!这样很不好,原因如下:
- 第一,假如你在A、B、C三个页面都用到了name,那么你要在这A、B、C三个页面都修改一遍,多个页面你就要加很多遍这个方法,造成代码冗余,很不好;
- 第二,假如下次产品经理让你把 “hello” 改成 “fuck” 的时候,你又得把三个页面都改一遍,这时候你只能抽自己的脸了…
那么应该如何?
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const state = { name: '张三', }; const getters = { getMessage(state) { // 获取修饰后的name,第一个参数state为必要参数,必须写在形参上 return `hello${state.name}`; } }; const mutations = {}; const actions = {}; export default new Vuex.Store({ state, getters, mutations, actions, });在组件中使用:
export default { mounted() { // 注意不是$store.state了,而是$store.getters console.log(this.$store.state.name); console.log(this.$store.getters.getMessage); } }
3.2.1、…mapGetters
-
官方建议: 是不是每次都写this.$store.getters.XXX让你感到厌烦,你实在不想写这个东西怎么办,当然有解决方案,官方建议我们可以使用mapGetters去解构到计算属性中,就像使用mapState一样,就可以直接使用this调用了,就像下面这样:
<script> import { mapState, mapGetters } from 'vuex'; export default { mounted() { console.log(this.name); console.log(this.getMessage); }, computed: { ...mapState(['name']), ...mapGetters(['getMessage']), }, } </script> -
当然,和mapState一样你也可以取别名,取外号,就像下面这样:
...mapGetters({ aliasName: 'getMessage' }), // 赋别名的话,这里接收对象,而不是数组
OK,当你看到这里,你已经成功的把Getter用起来了,你也能明白在什么时候应该用到getters,你可以通过计算属性访问(缓存),也可以通过方法访问(不缓存),你甚至可以在getters的方法里面再调用getters方法,当然你也实现了像state那样,使用mapGetters解构到计算属性中,这样你就可以很方便的使用getters啦!
读取值的操作我们有 “原生读(state)” 和 “修饰读(getters)”,接下来就要介绍怎么修改值了!
3.3、修改值:Mutation
3.3.1、修改state中的值
-
修改store/index.js
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); // 定义值 const state = { name: '张三', }; // 修饰器 const getters = { getMessage(state) { // 获取修饰后的name,第一个参数state为必要参数,必须写在形参上 return `hello${state.name}`; } }; // 修改值 const mutations = { setNumber(state) { // 增加一个mutations的方法,方法的作用是让num从0变成5,state是必须默认参数 state.number = 5; } }; // 异步修改值 const actions = {}; export default new Vuex.Store({ state, getters, mutations, actions, }); -
组件中使用
<script> export default { mounted() { console.log(`旧值:${this.$store.state.number}`); this.$store.commit('setNumber'); console.log(`新值:${this.$store.state.number}`); }, } </script>
3.3.2、给mutations中的方法传参
-
修改store/index.js
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); // 定义值 const state = { name: '张三', }; // 修饰器 const getters = { getMessage(state) { // 获取修饰后的name,第一个参数state为必要参数,必须写在形参上 return `hello${state.name}`; } }; // 修改值 const mutations = { setNumber(state) { // 增加一个mutations的方法,方法的作用是让num从0变成5,state是必须默认参数 state.number = 5; }, setNumberIsWhat(state, number) { // 增加一个带参数的mutations方法 state.number = number; }, }; // 异步修改值 const actions = {}; export default new Vuex.Store({ state, getters, mutations, actions, }); -
组件中使用
<script> export default { mounted() { console.log(`旧值:${this.$store.state.number}`); this.$store.commit('setNumberIsWhat', 666); console.log(`新值:${this.$store.state.number}`); }, } </script> -
注意:上面的这种传参的方式虽然可以达到目的,但是并不推荐,官方建议传递一个对象进去,这样看起来更美观,对象的名字你可以随意命名,但我们一般命名为payload,代码如下:
-
修改store/index.js
// 修改值 const mutations = { setNumber(state) { // 增加一个mutations的方法,方法的作用是让num从0变成5,state是必须默认参数 state.number = 5; }, setNumberIsWhat(state, payload) { // 增加一个带参数的mutations方法,并且官方建议payload为一个对象 state.number = payload.number; }, }; -
组件中使用
<script> export default { mounted() { console.log(`旧值:${this.$store.state.number}`); this.$store.commit('setNumberIsWhat', { number: 666 }); // 调用的时候也需要传递一个对象 console.log(`新值:${this.$store.state.number}`); }, } </script> -
此时可以得到和之前一样的效果,并且代码更加美观!
-
3.3.3、…mapMutations
-
官方建议:就像最开始的mapState和mapGetters一样,我们在组件中可以使用mapMutations以代替this.$store.commit(‘XXX’),是不是很方便呢?
<script> import { mapMutations } from 'vuex'; export default { mounted() { this.setNumberIsWhat({ number: 999 }); }, methods: { // 注意,mapMutations是解构到methods里面的,而不是计算属性了 ...mapMutations(['setNumberIsWhat']), }, } </script> -
当然你也可以给它叫别名,取外号,就像这样:
methods:{ ...mapMutations({ setNumberIsAlias: 'setNumberIsWhat' }), // 赋别名的话,这里接收对象,而不是数组 }
3.3.4、注意事项
- Mutations里面的函数必须是同步操作,不能包含异步操作!
3.4、异步操作:Actions
- Actions存在的意义是假设你在修改state的时候有异步操作,vuex作者不希望你将异步操作放在Mutations中,所以就给你设置了一个区域,让你放异步操作,这就是Actions
3.4.1、异步修改state中的值
-
修改store/index.js
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); // 定义值 const state = { name: '张三', }; // 修饰器 const getters = { getMessage(state) { // 获取修饰后的name,第一个参数state为必要参数,必须写在形参上 return `hello${state.name}`; } }; // 修改值 const mutations = { setNumber(state) { // 增加一个mutations的方法,方法的作用是让num从0变成5,state是必须默认参数 state.number = 5; }, setNumberIsWhat(state, payload) { // 增加一个带参数的mutations方法,并且官方建议payload为一个对象 state.number = payload.number; }, }; // 异步修改值 const actions = { setNum(content) { // 增加setNum方法,默认第一个参数是content,其值是复制的一份store return new Promise(resolve => { // 我们模拟一个异步操作,1秒后修改number为888 setTimeout(() => { content.commit('setNumberIsWhat', { number: 888 }); resolve(); }, 1000); }); } }; export default new Vuex.Store({ state, getters, mutations, actions, }); -
组件中使用
async mounted() { console.log(`旧值:${this.$store.state.number}`); await this.$store.dispatch('setNum'); console.log(`新值:${this.$store.state.number}`); }, -
官方建议:在store/index.js中的actions里面,方法的形参可以直接将commit解构出来,这样可以方便后续操作:
// 异步修改值 const actions = { setNum({ commit }) { // 增加payload参数 return new Promise(resolve => { setTimeout(() => { commit('setNumberIsWhat', { number: 888 }); resolve(); }, 1000); }); } }; -
看了例子,是不是明白了,action就是去提交mutation的,什么异步操作都在action中消化了,最后再去提交mutation的。
3.4.2、给action中的方法传参
-
修改store/index.js
// 异步修改值 const actions = { setNum(content, payload) { // 增加payload参数 return new Promise(resolve => { setTimeout(() => { content.commit('setNumberIsWhat', { number: payload.number }); resolve(); }, 1000); }); } }; -
组件中使用
async mounted() { console.log(`旧值:${this.$store.state.number}`); await this.$store.dispatch('setNum', { number: 611 }); console.log(`新值:${this.$store.state.number}`); },
3.4.3、…mapActions
-
官方建议:你如果不想一直使用this.$store.dispatch(‘XXX’)这样的写法调用action,你可以采用mapActions的方式,把相关的actions解构到methods中,用this直接调用:
<script> import { mapActions } from 'vuex'; export default { methods: { ...mapActions(['setNum']), // 就像这样,解构到methods中 }, async mounted() { await this.setNum({ number: 123 }); // 直接这样调用即可 }, } </script> -
当然,你也可以取别名,取外号,就像下面这样:
...mapActions({ setNumAlias: 'setNum' }), // 赋别名的话,这里接收对象,而不是数组
作者:三年没洗澡
链接:https://juejin.cn/post/6928468842377117709
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4、vuex模块化
-
修改store/index.js
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); // 模块1 const aaa = { // 开启命名空间 namespaced: true, // 定义值 state: { name:'张三' }, // 修饰器 getters: {}, // 修改值 mutations: {}, // 异步修改值 actions: {}, } // 模块2 const bbb = { // 开启命名空间 namespaced: true, // 定义值 state: { name:'李四' }, // 修饰器 getters: {}, // 修改值 mutations: {}, // 异步修改值 actions: {}, } export default new Vuex.Store({ modules: { aaa, bbb } }); -
组件中使用
mounted(){ console.log(this.aaa); //张三 console.log(this.bbb); //李四 }, computed:{ // 第一个值为模块名,第二个值为要取的属性名 ...mapState('aaa',{aaa: 'name'}), ...mapState('bbb',{bbb: 'name'}), }