Vuex的五大核心模块使用详解

Posted 忘忘碎斌bin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vuex的五大核心模块使用详解相关的知识,希望对你有一定的参考价值。

image-20210708212816397
从安装到Vuex常见使用和细节的保姆级讲解。

Vuex的基本安装与配置

  • 安装:npm install vuex@next
  • 开发目录结构,在新建src/store/index.js路径文件。在 index.js内配置。
─src
    │  App.vue
    │  main.js
    ├─assets
    │      logo.png
    ├─components
    └─store
            index.js
  • Vuex的配置

index.js

import { createStore } from "vuex";
const store = createStore({
    state(){return {}},
    getters: {},
    mutations: {},
    actions: {},
    modules: {}
});
export default store

main.js use进行注册

import { createApp } from 'vue'
import App from './App.vue'
import store from './store/index'
createApp(App).use(store).mount('#app')

Vuex有五大核心模块:stategettersmutationsactionsmodule

接下来,接下来 从 template直接使用,到 Option API内的使用,再到 composition API内的使用。

核心模块一:state

基本使用

state简而言之就是用来存放一些数据,这些数据可以在任何一个页面内进行使用。

image-20210708220351950

  • template内直接通过$store.state对象来取值。
  • Option API中 通过 this.$store.state对象来取值。
  • Composition API 中:需要用到 vuex提供的useStore
<script>
import { computed } from 'vue'
import {useStore} from 'vuex'
export default {
  setup(){
      const store = useStore();
      const address = computed( _ => store.state.address) ;
      const info = computed( _ => store.state.info) ; 
      return {
        address,
        info
      }
  }
}
</script>

mapState的辅助函数

辅助函数:用来解决获取数据而路径太长的情况。一般是放在computed使用。

  • Option API中使用辅助函数。

参数为数组时,将state内的哪些数据映射过来,就填什么,在template使用直接用数组内的名字

<script>
import { mapState} from 'vuex'
export default {
  computed:{
      ...mapState(['address','info'])
  }
}
</script>

参数为对象时,可以进行名字state数据做名字的映射,使用自定义的名字

<script>
import { mapState} from 'vuex'
export default {
  computed:{
      ...mapState({
          sInfo:'info',
          sAddress: state => state.address
      })
  }
}
</script>
  • Composition API中使用辅助函数

一个一个取

<script>
import {useStore,mapState} from 'vuex'
import {computed} from 'vue'
export default {
  setup(){
      const store = useStore();
      const address = computed(()=>store.state.address);
      const info = computed(()=>store.state.info)
      return {
        address,
        info
      } 
  }
}
</script>

mapState返回的是一个对象: { address:function } 直接解雇setup返回,页面内使用是一个函数。 在使用mapState时本质内部还是使用this.$store.state。但是 setup里面是没有 this 的

在取到对应函数后 手动改变this指向

<script>
import {useStore,mapState} from 'vuex'
import {computed} from 'vue'
export default {
  setup(){
    const store = useStore();
    const storeFns =  mapState(['address','info']);
    let finallStore = {}  
    for(let fn of Object.keys(storeFns)){
        const fun = storeFns[fn].bind({$store:store})
        finallStore[fn] = computed(fun)
    }
      return {
        ...finallStore
      } 
  }
}
</script>

其实可以封装成一个函数,但是可以和 getters的辅助函数一起封装,后面一起封装。

核心模块二:getters

store/index.js state中加入一条数据。

books: [{ name: 'Vuejs入门到放弃', prices: 60 }, { name: 'JS高级', prices: 50 }, { name: 'nodejs', prices: 55 }]

其他页面可能会用到 计算书的总价格。为了避免在不同的页面都写同样的求和逻辑,可以在 getters内完成一个求和的逻辑,其他页面只需要直接引用就可。

基本使用

getters: {
    booksPrice(state) {
        return state.books.reduce((preV, newV) = >{
            return preV + newV.prices
        },
        0)
    }
}
  • template内直接通过$store.getters对象来取值。
  • Option API中 通过 this.$store.getters对象来取值。
  • Composition API 中:需要用到 vuex提供的useStore
<script>
import { computed } from 'vue'
import { useStore } from "vuex";
export default {
  setup(){
      const store = useStore();
      const bookPrice = computed(()=> store.getters.booksPrice)
      return {
        bookPrice
      } 
  }
}
</script>

mapGetters的辅助函数

辅助函数:用来解决获取数据而路径太长的情况。一般是放在computed使用。

mapGetters传入对象,自定义名字

  • Option API中使用辅助函数。
import { mapGetters } from "vuex";
...
computed:{
  ...mapGetters(['booksPrice'])
}
  • Composition API中使用辅助函数

与state一样,需要手动修改this指向

<script>
import { useStore,mapGetters} from "vuex";
import { computed } from "vue";
export default {
  setup(){
    const store = useStore();
    let finallStore = {}
    const storeFns = mapGetters(['booksPrice'])
    for(let fn of Object.keys(storeFns)){
        const fun = storeFns[fn].bind({$store:store});
        finallStore[fn] = computed(fun);
    }
      return {
        ...finallStore
      } 
  }
}
</script>

封装

image-20210709092800331

getters的第二个参数

getters里面的方法,可能又依赖getters里的另一个方法,第二个参数就是整个getters对象,通过 .的方法使用其他方法。

核心模块三:mutations

用来修改state里面的值,在mutations里面设置方法,然后再组件内提交方法名,调用对应的方法,修改对应的state内的属性值。

基本使用

  • 在mutations内设置相应的方法。 第一个参数 state:可以取到state内的值,第二个参数:payload,在提交时取到传递过来的参数。
mutations: {
  changeCounter(state, payload) {
    state.counter = state.counter + payload
  }
}
  • 在 **option API **内使用

通过 commit方法提交

methods: {
  increment() {
    this.$store.commit('changeCounter', 1)
  }
}

另一种提交风格

methods: {
  increment() {
    this.$store.commit({
        type: 'changeCounter',
        num: 1
    })
  }
}
  • composition API中使用。通过 useStore方法取到 store后 里面同样有 commit 方法。
<script>
import { useStore} from "vuex";
export default {
name: "Home",
  setup(){
    const store = useStore()
    const increment = ()=>{
      store.commit('changeCount',1);
    }
    const decrement = _=>{
      store.commit({
      type:'changeCount',
      num:-1
    })
    }
    return{
      increment,
      decrement
    }
  }
}
</script>

mapMutations辅助函数

直接映射到方法中。

mapMutations传入对象,自定义名字

  • 在 **option API **内使用
import {mapMutations} from "vuex";
......
methods: {
  ...mapMutations(['changeCounter']),
   //  自定义名字 
  ...mapMutations({
      aChangeCounter :'changeCounter'
  })
}
  • composition API中使用

直接返回

<script>
import {mapMutations} from 'vuex'
export default {
  setup(){
      return {
        ...mapMutations(['changeCounter'])
      } 
  }
}
</script>

or

<script>
import {mapMutations} from 'vuex'
export default {
  setup(){
    const useMutations = mapMutations(['changeCounter'])
      return {
        ...useMutations
      } 
  }
}
</script>

Mutation常量类类型

  • mutation-type.js

  • store/index.js中
import { INCREMENT } from "./mutation-type";
.......
mutations: { 
    [INCREMENT](state, payload) {
      state.counter = state.counter + payload
  }
}
  • 组件内
import { INCREMENT } from "../store/mutation-type";
......//此处代码省略
...mapMutations([INCREMENT])

核心模块四:actions

假如数据的改变,是在异步函数操作之后,在actions内编写异步函数,再在actions内提交给mutations对state做出改变。主要是为了在配合Vue devtools 使用时,都能监听到数据改变的细节

基本使用

  • 在actions内设置相应的方法,第一个参数 context上下文,和上面的的第一个参数不是一个意思,context包含的东西更多,整个store对象。第二个参数payload,在提交时取到传递过来的参数。

​ 异步操作用定时器代替。

actions: {
  delayChangeCount(context, payload) {
    console.log(context);
    setTimeout(_ = >{
      context.commit('changeCount', typeof payload === 'object' ? payload.num: payload)
    },
    1000)
  }
}
  • option API内使用

通过dispatch提交

methods: {
  increment() {
    this.$store.dispatch('delayChangeCount', 1)
  }
}

另一种提交风格

methods: {
   decrement() {
    this.$store.dispatch({
      type: 'delayChangeCount',
      num: -1
    })
  }
}
  • composition API内使用

    通过 vuex提供的 useStore

<script>
import { useStore,mapActions } from "vuex";
export default {
name: "Home",
  setup(){
   const store = useStore();
   const increment = _=>{
     store.dispatch('delayChangeCount',1)
   }
   // 第二种提交风格
   const decrement = _=>{
     store.dispatch({
       type:'delayChangeCount',
       num:-1
     })
   }
    return{
     increment,
     decrement
    }
  }
}
</script>

mapActions辅助函数

直接将actions内的函数映射到组件内。

  • option API
import { mapActions } from "vuex";
methods: {
  ...mapActions(['delayChangeCount']);
}
  • composition API

直接返回 or 先赋值对象,再结构返回

<script>
import {mapActions } from "vuex";
export default {
name: "Home",
  setup(){
    return{
      ...mapActions(['delayChangeCount'])
    }
  }
}
</script>

核心模块五:modules

假如整个项目放在一个state内,如果数据很多,可能会出现命名冲突,代码混乱的一些问题,通过modules进行分模块

基本使用

store/index.js

// 自定义的两个模块
import moduleA from './module/moduleA'
import moduleB from './module/moduleB'
 // ......代码省略
modules: {
  a: moduleA,
  b: moduleB
}

./module/moduleA.js 基本结构和index的结构差不多

export default {
    state() { return { count:100 } },
    getters: {},
    mutations: {},
    actions: {},
    modules: {}
}

组件内使用

  • 使用state时 ,使用 moduleA内的state的数据:$store.state.a.xxxx,a 与再 modules内设置的key有关。
  • 使用模块内的getters、mutations、actions也默认注册在全局命名空间,不需要加模块名字了,直接调用使用。

module的命名空间

因为使用模块内的getters、mutations、actions是直接使用,但是希望模块具有更高的封装度和复用性,添加 namespaced: true (在子模块内添加)的方式使其成为带命名空间的模块,那么再使用getters、mutations、actions的时候就需要一定的调整

获取模块内getters

在模块内定义方法:四个参数

  • state本模块的state
  • getters本模块内的getters
  • rootState根模块内的state
  • rootGetters 根模块内的getters
getters: {
  getACount(state, getters, rootState, rootGetters) {
    console.log(rootgetter);
    return state.aCount * 2 + rootstate.count * 10
  }
}
  • template使用
<h5>moduleA getACount :{{$store.getters["a/getACount"]}}</h5>
  • options API内使用
computed: {
  getModuleACounte() {
    return this.$store.getters["a/getACount"]
  }
}
  • composition API中使用
<script>
import { computed } from "vue";
import { useStore } from "vuex";
export default {
name: "Home",
  setup(){
    const store = useStore();
    const aCount = computed(_=>store.getters["a/getACount"]);
    return{
      aCount
    }
  }
}
</script>

提交模块内的mutations

在模块mutations内定义方法 参数和 核心模块三 内的参数解释一样

mutations: {
  changeACount(state, payload) {
    state.aCount++;
  }
}

提交同样有两种提交代码的风格

**commit存在第三个参数[可选] **{root:true}是否派发个根组件

  • options API
this.$store.commit('a/changeACount',1)
  • composition API
<script>
import { useStore } from "vuex";
export default {
name: "Home",
  setup(){
    const store = useStore();
    const increment = ()=> {
      store.commit('a/changeACount',1)
    }
    return{
      increment
    }
  }
}
</script>

提交模块内的 actions

在模块actions内定义方法, context上下文(下面详细解释), payload 携带参数