Vuex 模块化详解

使用Vuex的好处

  1. 能够在Vuex中集中管理共享数据,易于开发和后期维护
  2. 能够高效地实现组件之间的数据共享,提高开发效率
  3. 在Vuex中的数据都是响应式的

Vuex的状态管理模式

在这里插入图片描述
在这里插入图片描述

为什么要用到Vuex Modules

在这里插入图片描述

Vuex Modules简单使用

我们在src目录下建立我们的store文件夹,用来写一些vuex module的简单使用。

1.index.js
// index.js
import Vue from 'vue'
import Vuex from 'vuex'
import { moduleA } from './moduleA'
import { moduleB } from './moduleB'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        count: 0,
        name: 'index'
    },
    mutations: {
        increment(state, payload) {
            state.count += payload.amount;
            console.log("mutations" + state.name)

        },
    },
    actions: {
        incrementAsync({ state, commit }, products) {
            setTimeout(() => {
                console.log("actions" + state.name)
                commit('increment', products)
            }, 1000)
        }
    },
    modules: { moduleA, moduleB },
    getters: {
        getCount: (state) => {
            return "store被调用了" + state.count + "次"
        }
    }
})

2.moduleA.js
// moduleA.js
export const moduleA = {
    state: {
        nameA: "moduleA",
        countA: 0
    },
    mutations: {
        incrementA(state, payload) {
            state.countA += payload.amount;
            console.log("mutations" + state.nameA)
        }
    },
    actions: {
        incrementAsyncA({ commit }, products) {
            setTimeout(() => {
                commit('incrementA', products)
                console.log("actions" + state.nameA)
            }, 1000)
        }
    },
    getters: {
        getCountA: (state, getters) => {
            console.log("getter" + state.nameA)
            return state.nameA + "被调用了" + state.countA + "次"
        }
    }
}

3.moduleB.js
// moduleB.js
export const moduleB = {
    state: {
        nameB: "moduleB",
        countB: 0
    },
    mutations: {
        incrementB(state, payload) {
            state.countB += payload.amount;
            console.log("mutations" + state.nameB)
        }
    },
    actions: {
        incrementAsyncB({ commit }, products) {
            setTimeout(() => {
                commit('incrementB', products)
                console.log("actions" + state.nameB)
            }, 1000)
        }
    },
    getters: {
        getCountB: (state, getters) => {
            console.log("getter" + state.nameB)
            return state.nameB + "被调用了" + state.countB + "次"
        }
    }
}

4.页面
<template>
  <div class="hello">
   <div>
     {{name}}
     <button @click="incrementFun">{{count}}</button>
     {{getCount}}
   </div>
   <div>
     {{nameA}}
     <button @click="incrementFunA">{{countA}}</button>
     {{getCountA}}
   </div>
   <div>
     {{nameB}}
     <button @click="incrementFunB">{{countB}}</button>
     {{getCountB}}
   </div>
  </div>
</template>

<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'

export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  computed:{
    ...mapState({
      count: state => state.count,
      name: state => state.name,
      countA: state => state.moduleA.countA,
      nameA: state => state.moduleA.nameA,
      countB: state => state.moduleB.countB,
      nameB: state => state.moduleB.nameB
    }),
    ...mapGetters([
      'getCount',
      'getCountA',
      'getCountB'
    ])
  },methods:{
    ...mapMutations([
      'increment',
      'incrementA',
      'incrementB'
    ]),
    ...mapActions([
      'incrementAsync',
      'incrementAsyncB',
      'incrementAsyncB'
    ]),
    incrementFun(){
      this.increment({amount:1})
      console.log(this.$store.state);
    },
     incrementFunA(){
      this.incrementA({amount:1})
    }, 
    incrementFunB(){
      this.incrementB({amount:1})
    }
  }
}
</script>

<style scoped>
</style>

我们需要注意的是,不同mutation以及action中函数的名字相同会出现函数被重复调用的情况。

模块的局部状态

对于模块内部的mutation和getter,接收到的第一个参数是模块的局部状态对象。

**在getter中,根节点状态会作为第三个参数暴露出来。

//moduleA.js
    mutations: {
        incrementA(state, payload) {
            state.countA += payload.amount;
            console.log(state);
        }
    },
    getters: {
        getCountA: (state, getters, rootState) => {
            console.log(state);
            console.log(rootState);
            return state.nameA + "被调用了" + state.countA + "次"
        }
    }

1.根据输出我们可以看到,这里的state只是moduleA的state对象。
2.同样,对于模块内部的action,局部状态通过context.state暴露出来,根节点状态则为context.rootState

// moduleA.js
    actions: {
        incrementAsyncA({ commit, state, rootState }, products) {
            setTimeout(() => {
                console.log(state);
                console.log(rootState);
                commit('incrementA', products)
            }, 1000)
        }
    }

在这里插入图片描述

命名空间

默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的,这样使得多个模块能够对同一mutation或action做出响应。

如果我们想让我们的模块具有更高的封装度和复用性,可以通过添加namespaced: true的方式使其成为带命名空间的模块。当模块被注册后,他的所有getter、action及matation都会自动根据模块注册的路径调整命名。

// index.js 只倒入moduleA
modules: { moduleA }

// moduleA
import { moduleB } from './moduleB'
import { moduleC } from './moduleC'

//moduleA.js
export const moduleA = {
    namespaced: true,
    state: {
        nameA: "moduleA",
        countA: 0
    },
    mutations: {
        incrementA(state, payload) {
            state.countA += payload.amount;
        }
    },
    actions: {
        incrementAsyncA({ commit, state, rootState }, products) {
            setTimeout(() => {
                commit('incrementA', products)
            }, 1000)
        }
    },
    getters: {
        getCountA: (state, getters, rootState) => {
            return state.nameA + "被调用了" + state.countA + "次"
        }
    },
  //嵌套子模块
    modules: {
        moduleB,
        moduleC
    }
}
// moduleB.js moduleB没有设置namespaced: true会继承父模块命名空间
export const moduleB = {
    state: {
        nameB: "moduleB",
        countB: 0
    },
    mutations: {
        incrementB(state, payload) {
            state.countB += payload.amount;
        }
    },
    actions: {
        incrementAsyncB({ commit }, products) {
            setTimeout(() => {
                commit('incrementB', products)
            }, 1000)
        }
    },
    getters: {
        getCountB: (state, getters) => {
            return state.nameB + "被调用了" + state.countB + "次"
        }
    }
}
//moduleC.js
export const moduleC = {
    namespaced: true,
    state: {
        nameC: "moduleC",
        countC: 0
    },
    mutations: {
        incrementC(state, payload) {
            state.countC += payload.amount;
        }
    },
    actions: {
        incrementAsyncC({ commit }, products) {
            setTimeout(() => {
                commit('incrementC', products)
            }, 1000)
        }
    },
    getters: {
        getCountC: (state, getters) => {
            return state.nameC + "被调用了" + state.countC + "次"
        }
    }
}

组件内使用:

<template>
  <div class="hello">
   <div>
     {{name}}
     <button @click="incrementFun">{{count}}</button>
     {{getCount}}
   </div>
   <div>
     {{nameA}}
     <button @click="incrementFunA">{{countA}}</button>
     {{getCountA}}
   </div>
   <div>
     {{nameB}}
     <button @click="incrementFunB">{{countB}}</button>
     {{getCountB}}
   </div>
    <div>
     {{nameC}}
     <button @click="incrementFunC">{{countC}}</button>
     {{getCountC}}
   </div>
  </div>
</template>

<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'

export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  computed:{
    ...mapState({
      count: state => state.count,
      name: state => state.name,
      countA: state => state.moduleA.countA,
      nameA: state => state.moduleA.nameA,
      countB: state => state.moduleA.moduleB.countB,
      nameB: state => state.moduleA.moduleB.nameB,
      countC: state => state.moduleA.moduleC.countC,
      nameC: state => state.moduleA.moduleC.nameC
    }),
    ...mapGetters({
      getCount: 'getCount',
      getCountA: 'moduleA/getCountA',
      getCountB: 'moduleA/getCountB',
      getCountC: 'moduleA/moduleC/getCountC'
    })
  },methods:{
    ...mapMutations({
      increment: 'increment',
      incrementA: 'moduleA/incrementA',
      incrementB: 'moduleA/incrementB',
      incrementC: 'moduleA/moduleC/incrementC'
    }),
    ...mapActions({
      incrementAsync: 'incrementAsync',
      incrementAsyncA: 'moduleA/incrementAsyncA',
      incrementAsyncB: 'moduleA/incrementAsyncB',
      incrementAsyncC: 'moduleA/moduleC/incrementAsyncC'
    }),
    incrementFun(){
      this.increment({amount:1})
    },
     incrementFunA(){
      this.incrementA({amount:1})
    }, 
    incrementFunB(){
      this.incrementB({amount:1})
    },
    incrementFunC(){
      this.incrementC({amount:1})
    }
  }
}
</script>

<style scoped>
</style>

在带命名空间的模块内访问全局内容

在这里插入图片描述

  // moduleA.js  
	actions: {
        incrementAsyncA({ dispatch, commit, getters, rootGetters }, products) {
            setTimeout(() => {
                console.log(rootGetters['moduleA/moduleC/getCountC'])
                commit('moduleA/incrementB', products, { root: true })
                commit('incrementA', products)
            }, 1000)
        }
    },
    getters: {
        getCountA: (state, getters, rootState, rootGetters) => {
            console.log(rootGetters.getCount)
            console.log(rootGetters['moduleA/getCountB'])
            return state.nameA + "被调用了" + state.countA + "次"
        }
    }

在这里插入图片描述

在带命名空间的模块注册全局action

若需要在命名空间的模块注册全局action,我们可以添加root: true,并将这个action的定义放在函数handler中

actions: {
        incrementAsyncA: {
            root: true,
            handler({ dispatch, commit, getters, rootGetters }, products) {
                setTimeout(() => {
                    commit('incrementA', products)
                }, 1000)
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值