【Vuex】回顾系列一(共用数据管理)

326 阅读4分钟

目录

  1. Vuex 是什么,解决什么问题
  2. Vuex 包含什么
  3. 使用方式:
  • 3.1【访问值】:state 和 getters 
  • 3.2【修改值】Mutation 
  • 3.3【异步】 action

一、Vuex 是什么,解决什么问题

是什么

vuex是一个专门为vue.js设计的集中式状态管理架构。状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性

解决什么问题

Vuex解决了什么问题?

解决两个问题

  • 多个组件依赖于同一状态时,对于多层嵌套的组件的传参将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
  • 来自不同组件的行为需要变更同一状态。以往采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

image.png

在src路径下创建store文件夹,然后创建index.js文件,文件内容如下: new 出来 store 对象

store/index.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        // 定义些数据,以供全局使用
        name: 'andy',
        age : 18
    },
});

export default store;

main.js

import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store'; // 引入我们前面导出的store对象

Vue.config.productionTip = false;

new Vue({
    el: '#app',
    router,
    store, // 把store对象添加到vue实例上
    components: { App },
    template: '<App/>'
});

二、 Vuex 包含什么

  • 1【访问值】:state 和 getters 
  • 2【修改值】Mutation 
  • 3【异步】 action

1. state (全局共享的状态,方便兄弟组件以及无关组件公用状态)

2. getters (修饰器)(简化代码,state数据修饰)

3. Mutation (修改值: 1. 直接修改。2. 在actions中修改)

4. Actions 异步操作

三、【访问值】state,getter 使用方式

1)this.$store.state.xxx

this.$store.state.xx this.$store.getters.XXX

<template>
    <div></div>
</template>

<script>
    export default {
        mounted() {
            // 使用this.$store.state.XXX可以直接访问到仓库中的状态
            console.log(this.$store.state.name); 
        }
    }
</script>

2)mapState

<script>
import { mapState } from 'vuex'; // 从vuex中导入mapState
export default {
    mounted() {
        console.log(this.name);
    },
    computed: {
        ...mapState(['name']), // 经过解构后,自动就添加到了计算属性中,此时就可以直接像访问计算属性一样访问它
    },
}
</script>

【修改值】mutation, action 使用方式

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        name: 'andy',
        number: 0,
    },
    mutations: { // 增加nutations属性
        setNumber(state) {  // 增加一个mutations的方法,方法的作用是让num从0变成5,state是必须默认参数
            state.number = 5;
        }
    },
});

export default store;

1)mutations 使用方式 this.$store.commit('mutations', payload)

  1. mutations 使用方式 - 【不传参】
  2. mutations 使用方式 - 【传参】
  3. mutations 使用方式 - 【payload 传参】
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        name: 'andy',
        number: 0,
    },
    mutations: { // 增加 mutations 属性
        setNumber(state) {  // 增加一个mutations的方法,方法的作用是让num从0变成5,state是必须默认参数
            state.number = 5;
        }
    },
});

export default store;

1.1) mutations 使用方式 - 【不传参】

this.$store.commit('xxx')

<script>
export default {
    mounted() {
        console.log(`旧值:${this.$store.state.number}`); // 0
        this.$store.commit('setNumber');
        console.log(`新值:${this.$store.state.number}`); // 5
    },
}
</script>

以上是简单实现 mutations 的方法,是没有传参的,如果我们想传不固定的参数怎么办?

1.2) mutations 使用方式 - 【传参】

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        name: 'andy',
        number: 0,
    },
    mutations: {
        setNumber(state) {
            state.number = 5;
        },
        setNumberIsWhat(state, number) { // 增加一个带参数的mutations方法
            state.number = number;
        },
    },
});

export default store;

<script>
export default {
    mounted() {
        console.log(`旧值:${this.$store.state.number}`); // 0
        this.$store.commit('setNumberIsWhat', 666);
        console.log(`新值:${this.$store.state.number}`); // 666
    },
}
</script>
  • 注意:上面的这种传参的方式虽然可以达到目的,但是并不推荐,官方建议传递一个对象进去,这样看起来更美观,对象的名字你可以随意命名,但我们一般命名为 payload,如下:

1.3) mutations 使用方式 - 【payload 传参】

修改store/index.js

增加一个带参数的mutations方法,并且官方建议payload为一个对象

mutations: {
    setNumber(state) {
        state.number = 5;
    },
    setNumberIsWhat(state, payload) { // 增加一个带参数的mutations方法,并且官方建议payload为一个对象
        state.number = payload.number;
    },
},

修改App.vue

<script>
export default {
    mounted() {
        console.log(`旧值:${this.$store.state.number}`); // 0
        this.$store.commit('setNumberIsWhat', { number: 666 });  // 调用的时候也需要传递一个对象
        console.log(`新值:${this.$store.state.number}`); // 666
    },
}
</script>

mutations使用方式 mapMutations

使用mapMutations解构到你的组件内部的methods里,这样你就可以很简单的使用mutations方法啦!

就像最开始的 mapStatemapGetters 一样,我们在组件中可以使用 mapMutations 以代替 this.$store.commit('XXX')

Mutations里面的函数必须是同步操作,不能包含异步操作!

<script>
import { mapMutations } from 'vuex';
export default {
    mounted() {
        this.setNumberIsWhat({ number: 999 });
    },
    methods: {   // 注意,mapMutations是解构到methods里面的,而不是计算属性了
        ...mapMutations(['setNumberIsWhat']),
    },
}
</script>

赋别名的话,这里接收对象,而不是数组

methods:{
    ...mapMutations({ setNumberIsAlias: 'setNumberIsWhat' })
}


2)actions 使用方式 dispatch

Actions存在的意义是假设你在修改state的时候有异步操作,vuex作者不希望你将异步操作放在Mutations中,所以就给你设置了一个区域,让你放异步操作,这就是Actions

2.1) setNum(content, payload)

修改store/index.js

const store = new Vuex.Store({
    state: {
        name: 'andy',
        number: 0,
    },
    mutations: {
        setNumberIsWhat(state, payload) {
            state.number = payload.number;
        },
    },
    actions: {   // 增加actions属性
        setNum(content) {  // 增加setNum方法,默认第一个参数是content,其值是复制的一份store
            return new Promise(resolve => {  // 我们模拟一个异步操作,1秒后修改number为888
                setTimeout(() => {
                    content.commit('setNumberIsWhat', { number: 888 });
                    resolve();
                }, 1000);
            });
        }
    }
});



修改App.vue

async mounted() {
    console.log(`旧值:${this.$store.state.number}`);
    // 旧值:0
    await this.$store.dispatch('setNum');
    console.log(`新值:${this.$store.state.number}`);
    // 1秒后打印 新值: 888
},

action 就是去提交mutation的,异步操作都在action中消化了,最后再去提交mutation的。

模仿mutation进行传参
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}`);
    // 旧值: 0
    await this.$store.dispatch('setNum', { number: 888 });
    console.log(`新值:${this.$store.state.number}`);
    // 1秒后打印 新值: 888
}

2.2) mapActions 解构到methods

你如果不想一直使用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>

官方建议: 在store/index.js中的actions里面,方法的形参可以直接将commit解构出来,这样可以方便后续操作

actions: {
    setNum({ commit }) {   // 直接将content解构掉,解构出commit,下面就可以直接调用了
        return new Promise(resolve => {
            setTimeout(() => {
                commit('XXXX');  // 直接调用 mutations
                resolve();
            }, 1000);
        });
    },
},


看到这里,你应该明白action在vuex的位置了吧,什么时候该用action,什么时候不用它,你肯定有了自己的判断,最主要的判断条件就是我要做的操作是不是异步,这也是action存在的本质。当然,你不要将action和mutation混为一谈,action其实就是mutation的上一级,在action这里处理完异步的一些操作后,后面的修改state就交给mutation去做了

参考

总结

  1. 创建store文件夹并在内创建index.js 中 new出来 store对象,并在main.js引入即可。
  2. mutation 功能就是修改state。【直接修改或者在actions中修改】
  3. store仓库特点,你可以随便拿,但是你不能随便改,必须按照store提供的方式修改值
  4. 使用方式:
  • 3.1【访问值】:state 和 getters 
  • 3.2【修改值】Mutation 
  • 3.3【异步】 action
  1. mutations 使用方式 this.$store.commit('mutations', payload)mapMutations

  2. action 就是去提交mutation的,异步操作都在action中消化了,最后再去提交mutation的。

  3. 不要将action和mutation混为一谈,action其实就是mutation的上一级,在action这里处理完异步的一些操作后,后面的修改state就交给mutation去做了

  4. mapActionsmapMutations 是解构到 methods 中

  5. mapStatemapGetters 是解构到 computed 中

  6. Vuex中4个属性都可以map。(此外,不map时,mutations是commit; actions是dispatch) (而state和getter不map时的使用方式是 this.$store.xx.xx)

  7. Vuex的5个核心属性是: state、getters、mutations、actions、modules 。