Vuex

简介​    

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

搭建环境

  创建主文件,通常为 src/store/index.js。

// src/store/index.js

// 引入Vue核心库
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 应用Vuex插件
Vue.use(Vuex)

// 准备actions对象
const actions = {}
// 准备mutations对象
const mutations = {}
// 准备state对象
const state = {}
// 准备getters对象
const getters = {}

// 创建并暴露store
export default new Vuex.Store({
   actions,
   mutations,
   state,
   getters
})
// main.js
......
// 引入store
import store from './store'
......

// 创建vm
new Vue({
   el:'#app',
   render: h => h(App),
   store
})

基本使用

  首先介绍 state、getters、actions、mutations 四个对象。

state

  state中主要用来存储需集中管理的数据。

  组件中读取 Vuex 中的数据可以采用如下方式(不要直接修改 Vuex 中的数据,修改使用 action 或 mutations )。

this.$store.state.XXX

getters

  当state中数据需要加工时,可使用getters加工后再使用。

  例如:

// 获取10倍的数据
const getters = {
// bigSum(state){
return state.sum*10 } }

  使用:

this.$store.getters.bigSum

  getters有一个默认参数 state,可直接获取state中的数据。

  正常情况下getters无需传参,但若想传参,可以采用一个小技巧,即返回一个函数,如下所示:

// 获取n倍的数据
const getters = {
    bigSum(state) => (n) =>  state.sum * n
}

  使用:

this.$store.getters.bigSum(10)

mutations

  用于操作数据(state)。
  mutations 中的方法通常有两个参数,一个是 state,一个是传入的 value。
const mutations = {
    JIA(state, value){
        // 执行操作的逻辑写在mutations中
        state.sum += value
    },
    JIAN(state, value){
        state.sum -= value
    }
}

  使用:

  通过 commit() 执行方法,需传入两个参数,一个是 mutations 中定义的方法名(字符串),一个是需要传入的数据。

methods: {
    add(){
        // 没有判断数据的逻辑,所以可以直接commit操作mutations
        this.$store.commit("JIA", this.n)
    },
    jian(){
        this.$store.commit("JIAN", this.n)
    },
}

actions

  actions 通常用于响应组件中的动作,比如在提交 mutations 前,用于执行一些判断逻辑等。

  如下所示,actions 的方法中通常包含两个参数:

    (1) context,可以使用其 context.commit() 方法提交 mutations ,或使用 context.state 直接操作数据。

    (2) value,待传入的数据。

const actions = {
    jishujia(context, value){
        // context上下文中也可获取到state数据
        // 用于判断数据的逻辑写在actions中
        if(context.state.sum % 2){
            context.commit("JIA", value)
        }
    },
    jiawait(context, value){
        setTimeout(() => {
            context.commit("JIA", value)
        }, 1000);
    }
}

  使用:

  通过 dispatch 执行actions中的方法,需传入两个参数,方法名和数据。

methods: {
    jishujia(){
        // 要通过actions层就要dispatch
        this.$store.dispatch("jishujia", this.n)
    },
    waitAdd(){
        this.$store.dispatch("jiawait", this.n)
    }
}

小结

  从上述介绍中我们可以总结出使用规律:

  (1)当需直接获取数据时,可使用 this.$store.state.XXX 获取数据。

  (2)当需直接获取加工后的数据时,可定义 getters 并通过 this.$store.getters.XXX 获取加工后的数据。

  (3)当有网络请求或其他业务逻辑,可使用 dispatch => actions提交动作 => mutations操作数据。

  (4)当无需判断或简单逻辑时,可直接使用 commit =>mutations操作数据。

四个map方法的使用

  每次使用时都需要 this.$store,太麻烦,Vue提供了一种映射方法可直接在组件内部操作Vuex,即为 mapState、mapGetters、mapActions 和 mapMutations。

引入

import {mapState, mapGetters, mapActions, mapMutations} from "vuex"

mapState

  需写入 computed 中,直接解构即可。

computed: {
   //借助mapState生成计算属性:sum、school、subject(对象写法)
   ...mapState({sum:'sum',school:'school',subject:'subject'}),
      
   //借助mapState生成计算属性:sum、school、subject(数组写法)
   ...mapState(['sum','school','subject']),
}

mapGetters

  需写入 computed 中,直接解构即可。

computed: {
   //借助mapGetters生成计算属性:bigSum(对象写法)
   ...mapGetters({bigSum:'bigSum'}),

   //借助mapGetters生成计算属性:bigSum(数组写法)
   ...mapGetters(['bigSum'])
}

mapActions

  需写入methods中,直接解构即可。

methods:{
      //靠mapActions生成:incrementOdd、incrementWait(对象形式)
      ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

      //靠mapActions生成:incrementOdd、incrementWait(数组形式)
      ...mapActions(['jiaOdd','jiaWait'])
}

mapMutations

  需写入methods中,直接解构即可。

methods:{
      //靠mapActions生成:increment、decrement(对象形式)
      ...mapMutations({increment:'JIA',decrement:'JIAN'}),
      
      //靠mapMutations生成:JIA、JIAN(对象形式)
      ...mapMutations(['JIA','JIAN']),
}

  都解构到 computed 和 methods 中了,怎么使用就不用我多说了吧。

模块化和命名空间

  虽然Vuex用来集中管理数据,但是不同业务线的数据和方法都存放在一起也大大降低了代码的可读性。

  Vuex 提供了一个 modules 属性,可以用来将 store 分割成多个模块,如下所示:

// mathMoudule.js
const state = {
    count:1
}
const getters = {
    getBigCount(state){
        return state.count * 10
    }
}
const mutations = {
    add(state,value) {
        return state.count + value
    },
}

export default {
    namespaced: true,
    state,
    mutations
}
// index.js
import Vue from "vue"
import Vuex from "vuex"
// 引入模块
import mathModule from "./mathModule.js"

Vue.use(Vuex)

export default new Vuex.Store({
    modules:{
        // 添加模块
        mathModule
    }
})

  我们可以看到模块中有一个 namespaced 属性,其作用是用来赋予模块命名空间。

  默认情况下,若不设置 namespaced 或值为 false ,模块内部的 action、mutation 和 getter 是注册在全局命名空间的。

  如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。

  当模块被注册后,它的所有 state、getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

// state
this.$store.state.mathModule.count
...mapState('mathModule', ['count', 'xxx', 'xxxx'])

// getters
this.$store.getters["mathModule/getBigCount"]
...mapGetters('mathModule', ['getBigCount'])

// mutations
this.$store.commit("mathModule/add", 10)
...mapActions('mathModule', { mathModuleAdd: 'add' })

// actions 用法同上

 

posted @ 2022-12-24 00:01  邢韬  阅读(68)  评论(0编辑  收藏  举报