Vuex个人学习笔记

160 阅读2分钟

理解Vuex

什么是Vuex

概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

什么时候用Vuex

  1. 多个组件依赖于同一个状态
  2. 来自不同组件的行为需要变更同一状态

(比如日常项目中一个全局使用的弹窗,需要在很多组件控制其显示和隐藏)

Vuex的工作原理

Vuex是集中于MVC模式中的Model层,规定所有的数据操作必须通过action-mutation-state的流程来进行,再结合Vue的数据视图v-model等双向绑定特性来实现页面的展示更新。如图所示: image.png 简述主要方法详情:

  • Vue Components:Vue组件。展示页面,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
  • dispatch:操作行为触发方法。是唯一能执行action的方法。
  • actions:操作行为处理模块。处理Vue Components 接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册顺序依次触发。像后台API请求的操作就在这个模块进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。
  • commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
  • mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
  • state:页面状态管理容器对象。集中存储Vue Components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态u更新。

总结一句话:

Vue组件接收交互行为,调用dispatch方法触发action相关处理,若页面状态需要改变,则调用commit方法提交mutation修改state,通过getters获取到state新值,响应数据或状态给Vue 组件,界面随之更新。

以案例走一遍Vuex完整流程

App.vue

<template>
  <div>
    <h1> 当前求和为:{{ $store.state.sum }}</h1>
    <select v-model="n">
      <option :value="1">1</option>
      <option :value="2">2</option>
      <option :value="3">3</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementOdd">当前求和为奇数再加</button>
    <button @click="incrementWait">等一等再加</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      n: 1
    }
  },
  methods: {
    increment() {
      this.$store.commit('JIA', this.n)
    },
    decrement() {
      this.$store.commit('JIAN', this.n)
    },
    incrementOdd() {
      this.$store.dispatch('jiaOdd', this.n)
    },
    incrementWait() {
      this.$store.dispatch('jiaWait', this.n)
    }
  }
}
</script>
<style scoped></style>

store/index.js

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

Vue.use(Vuex);

// 创建一个新的 store 实例
export const store = new Vuex.Store({
    // state:用于存储数据
    state() {
        return {
            sum: 0
        }
    },
    // 准备actions--用于响应组件中的动作,此处适合处理一些业务逻辑
    // jia和jian由于没有什么业务逻辑无需走actions这一层,可以直接用mutations
    actions: {
        // jia(context, value) {
        //     context.commit('JIA', value)
        // },
        // jian(context, value) {
        //     context.commit('JIAN', value)
        // },
        jiaOdd(context, value) {
            if (context.state.sum % 2) {
                context.commit('JIA', value)
            }
        },
        jiaWait(context, value) {
            setTimeout(() => {
                context.commit('JIA', value)
            }, 500)
        }
    },
    // mutations:用于操作数据(state)
    mutations: {
        JIA(state, value) {
            this.state.sum += value
        },
        JIAN(state, value) {
            this.state.sum -= value
        }

    },

})

总结:对数据state的处理,完整流程是走actionsmutations这两步,actions主要处理一些业务逻辑,而mutations是用来直接改变state的一步。如果只是简单的改变一下state,则可以越过actions直接使用mutations一步到位。

getters配置项

Vuex允许我们在store中定义"getter"(可以认为store的计算属性)。就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

getters的作用

对于getters的理解主要作用是对state属性进行计算,可以理解类似于Vue中computed。

基本使用:

store/index.js

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

Vue.use(Vuex);

// 创建一个新的 store 实例
export const store = new Vuex.Store({
    state() {
        return {
            count: 0
        }
    },
    mutations: {
        increment(state) {
            state.count++
        }
    },
    getters: {
        getNum(state) {
            return state.num
        },
        getCount(state) {
            return state.count
        }
    }
})

App.vue

<template>
  <div>
    {{ count }}
    <button @click="add">Add State</button>
  </div>
</template>

<script>
export default {
  data() {
    return {}
  },
  computed: {
    count() {
      return this.$store.getters.getCount
    }
  },
  methods: {
    add() {
      this.$store.commit('increment')
    }
  }
}
</script>
<style scoped></style>

mapGetters辅助函数写法

<template>
  <div>
    {{ getCount }}
    <button @click="add">Add State</button>
  </div>
</template>

<script>
import { mapGetters } from 'vuex';
export default {
  data() {
    return {}
  },
  computed: {
    count() {
      return this.$store.getters.getCount
    },
    ...mapGetters(['getCount'])
  },
  methods: {
    add() {
      this.$store.commit('increment')
    }
  }
}
</script>
<style scoped></style>

Vuex模块化+命名空间

1. 定义模块(Module)

在Vuex中,每个模块是一个包含以下属性的对象:

  • state: 模块内部的状态对象,存储模块特有的数据。
const myModule = {
  state: {
    count: 0,
    // 其他状态属性...
  },
};

2. 模块的getters

类似于全局状态的getters,模块内部也可以定义getters,它们是基于模块状态的计算属性:

const myModule = {
  // ...
  getters: {
    doubledCount: (state) => state.count * 2,
    // 其他getter...
  },
};

3. 模块的mutations

模块的mutations负责同步更新模块状态,遵循全局mutations同样的规则:

const myModule = {
  // ...
  mutations: {
    increment(state) {
      state.count++;
    },
    decrement(state) {
     state.count--;
    },
    // 其他mutations...
  },
};

4. 模块的actions

模块的actions用于处理异步逻辑或者包含复杂业务流程的操作,它们通过调用commit来触发模块内的mutations

const myModule = {
  // ...
  actions: {
    asyncIncrement({ commit }) {
      setTimeout(() => {
        commit('increment');
      }, 1000);
   },
    asyncDecrement({ commit }) {
      // 异步操作后提交mutation
    },
    // 其他actions...
  },
};

5. 在组件中使用模块化Vuex

访问模块的stategetters

  • 直接访问:使用this.$store.state.myModule.countthis.$store.getters['myModule/doubledCount']
  • 组件计算属性或辅助函数:使用mapStatemapGetters辅助函数将模块状态映射到组件的计算属性。
import { mapState, mapGetters } from 'vuex';

export default {
  computed: {
    ...mapState('myModule', ['count']),
    ...mapGetters('myModule', ['doubledCount']),
  },
};

触发模块的mutationsactions

  • 使用commit调用模块内mutations

    this.$store.commit('myModule/increment');
    
  • 使用dispatch调用模块内actions

    this.$store.dispatch('myModule/asyncIncrement');
    

或者,同样可以使用mapMutationsmapActions辅助函数将模块的mutationsactions映射为组件方法:

import { mapMutations, mapActions } from 'vuex';

export default {
  methods: {
    ...mapMutations('myModule', ['increment']),
    ...mapActions('myModule', ['asyncIncrement']),
  },
};

6. 跨模块访问

  • 若要从一个模块的actiongetter访问另一个模块的stategettersactionsmutations,可以通过context参数:

    • action中:
      someAction({ dispatch, commit, rootState, rootGetters, getters, state }) {
        // 使用rootState、rootGetters访问全局状态和getter
        // 使用getters、state访问当前模块的状态和getter
        // 使用dispatch('otherModule/action')或commit('otherModule/mutation')调用其他模块的方法
      }
      
  • 若在组件中跨模块访问,直接通过$store的相应方法指定模块路径即可。

Vuex持久化存储

juejin.cn/post/697391…