• vuex详解


    vuex 概述

    Vue 中,组件之间共享数据的方式有:

    • 父组件向子组件传值:v-bind 属性绑定,例如: :data="products"
    • 子组件向父组件传值:v-on 事件绑定,例如:@click="clickMe"
    • 兄弟组件之间共享数据:EventBus 事件总线,例如:$emit 用于发送数据的组件,$on 用于接受数据的组件

    以上三种方案只适合在小范围内实现数据共享,如果我们要频繁的或者说在大范围内实现数据共享,那么就需要用到 vuex 了。

    Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据共享。

    画图

    使用 Vuex 统一管理状态的好处

    • 能够在 Vuex 中集中管理共享的数据,易于开发和后期维护
    • 能够高效的实现组件之间的数据共享,提高开发效率
    • 存储在 Vuex 中的数据都是响应式的,能够实时保持数据与页面的同步,即:若存储在 Vuex中的数据发生了变化,那么那些引用了全局的数据的组件也能够实时的进行页面刷新

    一般情况下,只有组件之间共享的数据,才会必要存储到 vuex 中,对于组件中的私有数据,依旧存储在组件自身的 data 中即可。

    Vuex的基本使用

    1、安装依赖包

    npm i vuex --save
    
    或
    
    yarn add vuex
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、在 store/index.js 中导入

    import Vuex from "vuex";
    
    Vue.use(Vuex);
    
    • 1
    • 2
    • 3

    3、创建store对象,在 store/index.js

    export default new Vuex.Store({
      // state中存放的就是全局共享的数据
      state: { count: 100 },
      getters: {},
      mutations: {},
      actions: {},
      modules: {},
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4、将store对象挂载到vue实例中,在 main.js

    new Vue({
      router,
      // 将创建的共享数据对象,挂载到Vue实例中,所有的组件,就可以直接从store中获取全局的数据了
      store,
      render: (h) => h(App),
    }).$mount("#app");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上述步骤其实在我们创建项目的时候就已经完成了,这里只需了解即可。

    Vuex的核心概念

    Vuex 中的主要核心概念如下:

    • State
    • Mutation
    • Action
    • Getter

    State

    Vuex中,State提供唯一的公共数据源,所有共享的数据都要统一放到State中进行存储,例如这里的Store相当于一个用于存储数据的公共容器。

    export default new Vuex.Store({
      state: { count: 100 },
      mutations: {},
      getters: {},
      actions: {},
      modules: {},
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上述代码,我们存储了一个 count 变量,默认值 100,那么我们该如何访问到这个变量的值呢?

    1、组件访问State中数据的第一种方式

    # 格式:
    this.$store.state.全局数据名称
    
    # 示例:由于我们是在 html 元素中调用,则可以省略 this。在 HomeView.vue 中
    
    <template>
      <div id="home">
        {{ $store.state.count }}
      </div>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    请添加图片描述

    2、组件访问State中数据的第二种方式

    通过mapState辅助函数的方式,将当前组件需要的全局数据,映射为computed 计算属性,在 HomeView.vue

    <template>
      <div id="home">
        <!--直接在组件中获取属性-->
        {{ count }}
      </div>
    </template>
    
    <script>
      import { mapState } from "vuex";
      export default {
        computed: {
          // ...表示展开映射,意思就是将全局属性映射为当前组件的计算属性
          ...mapState(["count"]),
        },
      };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Mutation

    • 需求:我们需要让全局变量 count 的值加 1

    1、原始方法,在 HomeView.vue 中,修改代码

    <template>
      <div id="home">
        <h3>{{ $store.state.count }}</h3>
    
        <button @click="incrementCount1">点我+1</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {};
      },
      methods: {
        incrementCount1() {
          this.$store.state.count++;
        },
      },
    };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    请添加图片描述

    解析:

    我们可以看到上述代码确实已经实现了我们想要的功能,但是在 Vuex 中,不允许组件直接去修改 store 中的数据,这种代码完全是不合法的,为什么不合法呢?
    当全局 state数据发生变化,我们就需要一个一个组件的去找,看是哪个组件修改了 state,这种方式不利于我们后期的维护
    如果我们使用 mutation 里面的函数来修改 state 的话,当发现 state 里面的数据修改的有问题,那么我们只需要直接来找 mutation 即可

    Vuex中,只能通过mutation变更Store中的数据,不可以直接操作Store中的数据。虽然通过mutation的方式来操作数据,虽然繁琐了一点,但是却可以集中监控所有数据的变化。

    2、使用 mutation

    store/index.js

    export default new Vuex.Store({
      state: { count: 100 },
      mutations: {
        // 1、定义 add 方法用于改变 state 中 count 的属性值
        add(state) {
          state.count++;
        },
      },
      getters: {},
      actions: {},
      modules: {},
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    HomeView.vue 中,

    <template>
      <div id="home">
        <h3>{{ $store.state.count }}</h3>
    
        <button @click="incrementCount1">点我+1</button>
      </div>
    </template>
    
    <script>
      export default {
        data() {
          return {};
        },
        methods: {
          incrementCount1() {
            // 2、通过 commit 触发 mutations 中的 add 方法
            this.$store.commit("add");
          },
        },
      };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    请添加图片描述

    3、使用 mutation 并传参数

    store/index.js

    import Vue from "vue";
    import Vuex from "vuex";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: { count: 100 },
      mutations: {
        add(state) {
          state.count++;
        },
        // 1、定义 addN 方法,里面传两个参数,state代表哪个属性,n代表增加几个
        addN(state, n) {
          state.count += n;
        },
      },
      getters: {},
      actions: {},
      modules: {},
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    HomeView.vue 中,

    <template>
      <div id="home">
        <h3>{{ $store.state.count }}</h3>
    
        <button @click="incrementCount1">点我+1</button>
        <br />
        <br />
        <button @click="incrementCountN">点我+N</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {};
      },
      methods: {
        incrementCount1() {
          this.$store.commit("add");
        },
        incrementCountN() {
          // 2、通过 commit 触发 mutations 中的 addN 方法并传参数
          this.$store.commit("addN", 5);
        },
      },
    };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    总结:

    this.$store.commit() 是触发 mutation 的第一种方式。

    接下来我们演示 mutation 的第二种使用方式

    HomeView.vue 中,

    <template>
      <div id="home">
        <h3>{{ $store.state.count }}</h3>
    
        <button @click="incrementCount1">点我+1</button>
        <br />
        <br />
        <button @click="incrementCountN">点我+N</button>
      </div>
    </template>
    
    <script>
    // 1. 从vuex中按需导入mapMutations函数
    import { mapMutations } from "vuex";
    export default {
      data() {
        return {};
      },
      methods: {
        // 2、将add和addN方法映射为methods中的函数,供当前组件使用。
        ...mapMutations(["add", "addN"]),
        
        incrementCount1() {
          this.add();
        },
        incrementCountN() {
          this.addN(5);
        },
        
        // 或者直接在标签元素中直接@click="add()"
      },
    };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    对于 mutations 来说,只能够实现同步操作,不可以执行异步操作。

    Action

    案例:当点击 点我加1 按钮,实现等待一秒钟,使 count 的值加 1

    1、在 store/index.js

    import Vue from "vue";
    import Vuex from "vuex";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: { count: 100 },
      mutations: {
        add(state) {
          // 在 mutations 里面的 add 方法中设置延时器,当 触发 add 方法后,count 属性的值延时一秒改变
          setTimeout(() => {
            state.count++;
          }, 1000);
        },
        addN(state, n) {
          state.count += n;
        },
      },
      actions: {},
      getters: {},
      modules: {},
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    以上代码测试结果如图

    请添加图片描述

    我们可以看出,触发add函数后,页面上的值改变了,但是state的值并没有变化。所以我们不能在 mutations 里面执行异步操作。

    action 其实类似于 mutation,都是用来修改 state 中属性值的。不同之处在于:

    • action 提交的是 mutation,而不是直接变更状态。
    • action 可以包含任意异步操作。

    2、修改 store/index.js 中的代码

    import Vue from "vue";
    import Vuex from "vuex";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: { count: 100 },
      mutations: {
        add(state) {
          // 在 mutations 里面的 add 方法中设置延时器,当 触发 add 方法后,count 属性的值延时一秒改变
          // setTimeout(() => {
          //   state.count++;
          // }, 1000);
          state.count++;
        },
        addN(state, n) {
          state.count += n;
        },
      },
      actions: {
        // 通过context去调用mutation里面的add函数
        addAsync(context) {
          setTimeout(() => {
            // 在 action 中,不能直接修改state 中的数据,若要修改,必须通过 context.commit 触发某个 mutation
            context.commit("add");
          }, 1000);
        },
        // 通过context去调用mutation里面的addN函数,并传入参数n
        addNAsync(context, n) {
          setTimeout(() => {
            context.commit("addN", n);
          }, 1000);
        },
      },
      getters: {},
      modules: {},
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    3、触发actions的第一种方式,在 HomeView.vue 中,

    <template>
      <div id="home">
        <h3>{{ $store.state.count }}</h3>
    
        <button @click="incrementCount1">点我+1</button>
        <br />
        <br />
        <button @click="incrementCountN">点我+N</button>
      </div>
    </template>
    
    <script>
      export default {
        data() {
          return {};
        },
        methods: {
          // 异步的让 count 自增 1
          incrementCount1() {
            // dispatch 函数专门用来触发 action
            this.$store.dispatch("addAsync");
          },
          // 异步的让 count 自增 n
          incrementCountN() {
            this.$store.dispatch("addNAsync", 5);
          },
        },
      };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    请添加图片描述

    这时,我们看到页面上的值改变了,state 中的值也一并发生变化。

    总结:

    如果通过异步(读取接口)操作变更数据,必须通过action,而不能使用mutation,但是在action中还是要通过触发mutation的方式间接变更数据。

    4、触发actions的第二种方式,在 HomeView.vue 中,

    <template>
      <div id="home">
        <h3>{{ $store.state.count }}</h3>
    
        <button @click="incrementCount1">点我+1</button>
        <br />
        <br />
        <button @click="incrementCountN">点我+N</button>
      </div>
    </template>
    
    <script>
    // 1. 从vuex中按需导入mapActions函数
    import { mapActions } from "vuex";
    export default {
      data() {
        return {};
      },
      methods: {
        // 2. 将指定的 actions 函数,映射为当前组件的 methods 函数
        ...mapActions(["addAsync", "addNAsync"]),
        incrementCount1() {
          this.addAsync();
        },
        incrementCountN() {
          this.addNAsync(5);
        },
        // 3. 也可以在点击按钮中直接@click="addNAsync"
      },
    };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
  • 相关阅读:
    黑马程序:springboot
    如何估算transformer模型的显存大小
    基于SSH开发高校选课系统的设计与实现+论文 大作业源码 毕业设计
    react笔记_04jsx语法学习
    Vue----数据源中数组的操作
    存一个滤波器的截图。免的过段时间忘了
    生成对抗网络 GAN——Generative Adversarial Nets
    项目文章| PBJ(IF:13.8)发表稻曲病菌效应因子Uv1809增强组蛋白去乙酰化抑制水稻免疫的分子机制
    【大学英语视听说上】Topic Presentation
    什么是相对URL和绝对URL
  • 原文地址:https://blog.csdn.net/huangdj321/article/details/125617170