Vue2 - vuex 基础回顾

78 阅读2分钟

vuex

前置

注意:vue2 安装 vuex 需下载指定版本,否则会报vuex版本过高的错误

 npm install vuex@3.4.0 --save

核心概念

创建 store 并挂载

  • 创建 src/store.js

     // 导入 Vue Vuex
     import Vue from 'vue';
     import Vuex from 'vuex';
     ​
     Vue.use(Vuex);
     ​
     // 创建并暴露 store 实例
     export default new Vuex.Store({
       state: {},
       mutations: {},
       actions: {},
     });
    
  • main.js

     import Vue from 'vue';
     import App from './App.vue';
     ​
     // 引入 store
     import store from './store';
     ​
     Vue.config.productionTip = false;
     ​
     // 挂载 store
     new Vue({ store, render: h => h(App) }).$mount('#app');
    

state

定义共享状态变量的地方

  • 定义 - src/store.js

     import Vue from 'vue';
     import Vuex from 'vuex';
     ​
     Vue.use(Vuex);
     ​
     export default new Vuex.Store({
       // 定义数据
       state: {
         count: 0,
       },
       mutations: {},
       actions: {},
     });
    
  • 使用 - a.vue

    推荐使用 mapState

     <template>
       <!-- 
       使用 store 中 state 内定义的共享状态
         方法一:$store.state.状态名
         方法二: 1. 引入 vuex 中 mapState 方法
                 2. 在 computed 中 映射状态
                 3. template 中 直接使用
      -->
       <div>
         <h1>a 页面当前最新的 count 值为:{{ $store.state.count }}</h1>
         <h2>{{ count }}</h2>
       </div>
     </template>
     ​
     <script>
     import { mapState } from 'vuex';
     export default {
       computed: {
         ...mapState(['count']),
       },
     };
     </script>
    

mutations

集中修改 state 的状态的地方

  • 定义 - src/store.js

      mutations: {
         // 不传参写法
         add(state) {
           state.count++;
         },
     ​
         // 传参写法
         addN(state, step) {
           state.count += step;
         },
       },
    
  • 使用 - a.vue

    推荐使用 mapMutations

     <template>
       <div>
         <h2>{{ count }}</h2>
         <button @click="handleAdd">+1</button>
         <button @click="handleAddN">+N</button>
       </div>
     </template>
     <script>
     import { mapState, mapMutations } from 'vuex';
     export default {
       computed: {
         ...mapState(['count']),
       },
       methods: {
         /** 调用 mutations 中的方法
          * 方法一:
          *    没有参数:this.$store.commit('函数名')
          *    带参数  :this.$store.commit('函数名',参数)
          * 方法二:
          *    1. 引入 mapMutations
          *    2. 使用 ...mapMutations(['add'...]) 将 mutation 函数映射为 methods 方法
          *    3. this.方法名 调用
          * commit 的作用就是调用某个 mutation 函数
          * */
         ...mapMutations(['add', 'addN']),
         handleAdd() {
           // 修改 state 值,必须通过 mutations 方法修改,以下方法是错误示例
           // this.$store.state.count++;
     ​
           // this.$store.commit('add');
           this.add();
         },
         handleAddN() {
           // this.$store.commit('addN', 10);
           this.addN(20);
         },
       },
     };
     </script>
     ​
    

actions

异步函数 必须放在 actions 中,然后调用 mutation 中的修改函数。直接在 mutations 中修改状态无效

常见有 actions 函数中 发起异步请求

  • 定义 - src/store.js

       actions: {
         // 在 actions 中不能直接修改 state 中的数据,必须通过 context.commit() 来触发某个 mutation 函数 才行
     ​
         // 无参
         asyncAdd(context) {
           setTimeout(() => {
             context.commit('add');
           }, 2000);
         },
         // 带参
         asyncAddN(context, step) {
           setTimeout(() => {
             context.commit('addN', step);
           }, 2000);
         },
       },
    
  • 使用 - a.vue

     <template>
       <div>
         <h2>{{ count }}</h2>
         <button @click="handleAsyncAdd">async +1</button>
         <button @click="handleAsyncAddN">async +N</button>
               <!-- 使用 mapActions 简写 -->
         <!-- <button @click="asyncAdd()">async +1</button> -->
         <!-- <button @click="asyncAddN(6)">async +N</button> -->
       </div>
     </template>
     ​
     <script>
     import { mapState, mapMutations, mapActions } from 'vuex';
     export default {
       computed: {
         ...mapState(['count']),
       },
       methods: {
         /** 触发 actions 函数
          * 方法一:this.$store.dispatch('actions 函数名')
          * 方法二:
          * dispatch:专门来触发 actions 函数
          */
         ...mapActions(['asyncAdd', 'asyncAddN']),
         handleAsyncAdd() {
           // 无参
           // this.$store.dispatch('asyncAdd');
           this.asyncAdd();
         },
         handleAsyncAddN() {
           // 带参
           // this.$store.dispatch('asyncAddN', 30);
           this.asyncAddN(5);
         },
       },
     };
     </script>
    

getter

不会修改 store 中的原数据,只是对 store 中已有的数据进行加工形成新的数据,起到包装数据的作用,类似 vue 中 计算属性的作用

  • 定义 - src/store.js

       getters: {
         showCount: state => {
           return `当前最新的数据是【${state.count}】 `;
         },
       },
    
  • 使用 - a.vue

     <template>
       <!-- 
       调用 getters
       方法一:$store.getters.函数名
       方法二:
           1. 引入 mapGetters
           2. 在 computed 中 使用 ...mapGetters(['函数名']),
           3. template 中 直接使用
      -->
       <div>
         <h2>{{ count }}</h2>
         <!-- <h2>{{ $store.getters.showCount }}</h2> -->
         <h2>{{ showCount }}</h2>
       </div>
     </template>
     ​
     <script>
     import { mapState, mapGetters } from 'vuex';
     export default {
       computed: {
         ...mapState(['count']),
         ...mapGetters(['showCount']),
       },
     </script>
    

module

  • store/index.js

     // 导入 Vue Vuex
     import Vue from 'vue';
     import Vuex from 'vuex';
     ​
     Vue.use(Vuex);
     ​
     // 创建并暴露 store 实例
     export default new Vuex.Store({
       modules: {
         // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions
         user: {
           state: {
             count: 0,
           },
           mutations: {},
           actions: {},
         },
       },
     });
    
模块状态下 state 的使用
  • test.vue

     <template>
       <div>
         <h1>{{ $store.state.user.count }}</h1>
       </div>
     </template>
    
模块状态下 mutations 的使用
  • store/index.js

      modules: {
         // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions
         user: {
           state: {
             count: 0,
           },
           mutations: {
             add(state, step) {
               if ((step ?? '') === '') {
                 state.count++;
                 return;
               }
               state.count += step;
             },
           },
           actions: {},
         },
       },
    
  • test.vue

     <template>
       <div>
         <h1>{{ $store.state.user.count }}</h1>
         <button @click="handleAdd"> 点击++ </button>
         <button @click="$store.commit('add')"> 2222点击++ </button>
         <button @click="add()"> 辅助函数点击++ </button>
       </div>
     </template>
     ​
     <script>
     import { mapMutations } from 'vuex';
     export default {
       /**
        * 方法一:this.$store.commit('函数名')
        * 方法二:mapMutations 辅助函数
        * */
       methods: {
         ...mapMutations(['add']),
         handleAdd() {
           this.$store.commit('add');
         },
       },
     };
     </script>
    
命名空间锁🎈
  • store/index.js

     modules: {
         // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions
         user: {
           // 命名空间锁
           namespaced: true,
           state: {
             count: 0,
           },
           mutations: {
             add(state, step) {
               if ((step ?? '') === '') {
                 state.count++;
                 return;
               }
               state.count += step;
             },
           },
           actions: {},
         },
       },
    
  • 命名空间锁下调用 mutations 函数的两种方式 - test.vue

     <template>
       <div>
         <h1>{{ $store.state.user.count }}</h1>
         <button @click="handleAdd"> 点击++ </button>
         <button @click="$store.commit('user/add')"> 2222点击++ </button>
         <button @click="add()"> 辅助函数点击++ </button>
       </div>
     </template>
     ​
     <script>
     import { mapMutations } from 'vuex';
     export default {
       /**
        * 方法一:this.$store.commit('模块名/函数名')
        * 方法二:mapMutations 辅助函数
        * */
       methods: {
         ...mapMutations('user', ['add']),
         handleAdd() {
           this.$store.commit('user/add');
         },
       },
     };
     </script>
    
创建模块专用辅助函数🎈
  • store/index.js

     modules: {
         // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions
         user: {
           // 命名空间锁
           namespaced: true,
          //...
         },
       },
    
  • test.vue

     <template>
       <div>
         <h1>{{ $store.state.user.count }}</h1>
         <button @click="add(10)"> 点击++ </button>
       </div>
     </template>
     ​
     <script>
     // 创建模块专用辅助函数
     import { createNamespacedHelpers } from 'vuex';
     const { mapMutations } = createNamespacedHelpers('user');
     export default {
       methods: {
         ...mapMutations(['add']),
       },
     };
     </script>
    
getters 的使用
  • store/index.js

     // 创建并暴露 store 实例
     export default new Vuex.Store({
       getters: {
         count: state => state.user.count,
       },
       modules: {
         // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions
         user: {
           // 命名空间锁
           namespaced: true,
           state: {
             count: 0,
           },
           mutations: {
             add(state, step) {
               if ((step ?? '') === '') {
                 state.count++;
                 return;
               }
               state.count += step;
             },
           },
           actions: {},
         },
       },
     });
    
  • demo.vue

     <template>
       <div>
         <h1>{{ $store.getters.count }}</h1>
       </div>
     </template>
    

💥项目中 store 的拆分

image.png

  • main.js

     import Vue from 'vue';
     import App from './App.vue';
     ​
     // 引入 store
     import store from './store/index';
     ​
     Vue.config.productionTip = false;
     ​
     // 挂载 store
     new Vue({ store, render: h => h(App) }).$mount('#app');
    
  • store/index.js

     // 导入 Vue Vuex
     import Vue from 'vue';
     import Vuex from 'vuex';
     import getters from './getters';
     import user from './modules/user';
     ​
     Vue.use(Vuex);
     ​
     // 创建并暴露 store 实例
     export default new Vuex.Store({
       getters,
       modules: {
         user,
       },
     });
    
  • store/modules/user.js

     export default {
       // 开启 命名空间锁
       namespaced: true,
       state: {
         count: 0,
       },
       mutations: {
         add(state, step) {
           if ((step ?? '') === '') {
             state.count++;
             return;
           }
           state.count += step;
         },
       },
       actions: {},
     };
    
  • store.getters.js

     export default {
       count: state => state.user.count,
     };
    
  • App.vue

     <template>
       <div>
         <h1>{{ $store.getters.count }}</h1>
         <button @click="add(10)"> 点击++ </button>
       </div>
     </template>
     ​
     <script>
     // 创建模块专用辅助函数
     import { createNamespacedHelpers } from 'vuex';
     const { mapMutations } = createNamespacedHelpers('user');
     export default {
       methods: {
         ...mapMutations(['add']),
       },
     };
     </script>
    

    \