Vuex详解(五种状态)


备注: npm install vuex@next

1 .状态管理

1 .1单状态管理

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

1 . 1 .1单状态管理的代码实现

<template>
  <h2>{{ counter }}</h2>
  <button @click="counter + 1"></button>
  <button @click="counter - 1"></button>
</template>

<script>
export default {
  data() {
    return {
      counter: 0,
    };
  },
};
</script>

<style>
</style>

在这里插入图片描述

1 .2 Vuex的多状态管理

Vue已经帮我们做好了单个界面的状态管理,但是如果是多个界面呢?

  • 多个试图都依赖同一个状态(一个状态改了,多个界面需要进行更新)
  • 不同界面的Actions都想修改同一个状态(Home.vue需要修改,Profile.vue也需要修改这个状态)

也就是说对于某些状态(状态1/状态2/状态3)来说只属于我们某一个试图,但是也有一些状态(状态a/状态b/状态c)属于多个试图共同想要维护的

  • 状态1/状态2/状态3你放在自己的房间中,你自己管理自己用,没问题。
  • 但是状态a/状态b/状态c我们希望交给一个大管家来统一帮助我们管理!!!
  • 没错,Vuex就是为我们提供这个大管家的工具。

全局单例模式(大管家)

  • 我们现在要做的就是将共享的状态抽取出来,交给我们的大管家,统一进行管理。
  • 之后,你们每个试图,按照我规定好的规定,进行访问和修改等操作。
  • 这就是Vuex背后的基本思想。

图解
在这里插入图片描述

1.3 . Store

每一个Vuex应用的核心就是store(仓库):

  • store本质上是一个容器,它包含着你的应用中大部分的状态(state);

Vuex和单纯的全局对象有什么区别呢?

  • 第一:Vuex的状态存储是响应式的
  • 当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会被更新;
  • 第二:你不能直接改变store中的状态

改变store中的状态的唯一途径就显示提交(commit) mutation;

  • 这样使得我们可以方便的跟踪每一个状态的变化,从而让我们能够通过一些工具帮助我们更好的管理应用的状态;

使用步骤:

  • 创建Store对象;
  • 在app中通过插件安装;

创建Store对象=>Vue3

import { createStore } from "vuex";
const stort = createStore({
  state() {
    return {
      counter:0
    }
  },
});
export default stort;

  • 进行挂载
import vuex from './stort/index';
createApp(App).use(vuex).mount('#app')

App.vue =>委托给mutations进行处理

<template>
  <div class="id">
    <home />
    <br>
    <h2>{{ $store.state.counter }}</h2>
    <button @click="addClick()">加一</button>
    <button @click="redClick()">减一</button>
  </div>
</template>

<script>
export default {
  
  // 基本的状态管理实现
  methods: {
    addClick() {
      //  进行委托给Mutations处理=>委托的是事件不是数据
      this.$store.commit("addClick");
    },
    redClick() {
      this.$store.commit("redClick");
    },
  },
};
</script>
<style>
</style>

2. Vuex的核心概念(Options API)

2 .1 state的使用

概念:

  • State是提供唯一的公共数据源,所有共享的数据都要统一放到`Store的State中进行存储。
  • 如果状态信息是保存到多个Store对象中的,那么之后的管理和维护等都会变得特别困难,所以Vuex也使用了单一状态树(单一数据源Single
    Source of Truth)来管理应用层级的全部状态。
  • 单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护。
export default new Vuex.Store({  
    state: {    
        count: 0  
    }
}

State数据访问方式一 :

  • 通过this.$store.state.全局数据名称访问
<h3>当前最新Count值为:{{this.$store.state.count}}</h3>

State数据访问方式二 :

  • 从vuex中按需导入mapState函数
import { mapState } from 'vuex'
  • 通过刚才导入的mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性:
<template>
  <div>
    <h3>当前最新Count值为:{{ count }}</h3>
    <button>-1</button>
  </div>
</template><script>
import { mapState } from "vuex";export default {
  computed: {
    ...mapState(["count"])
    //上面的映射等价于
    // count(){
    //   return this.$store.state.user
    // }
    //对象写法
    // ...mapState(["counte"])
      ...mapState({
        count: state => state.counte,
      })
  }
};
</script>

2 .2 Mutation的使用

  • 如果果想修改count的值,我们可以直接在组件中对this.$store.state.count进行操作即可
<template>
  <div>
    <h3>当前最新Count值为:{{this.$store.state.count}}</h3>
    <button @click="add">+1</button>
  </div>
</template><script>
export default {
  methods: {
    add() {
      this.$store.state.count++;
    }
  }
};
</script>
  • 测试发现,这可以实现需求,完成+1操作。
  • 但是,这种方法在vuex中是严格禁止的(检测不到数据的变化),那要怎么做呢?这时,就需要使用Mutation了。

利用Mutation用于变更存储在Store中的数据。

注意点:

  • 通过mutation变更Store数据,不可以直接操作Store中的数据
  • 通过这种方式,虽然操作稍微繁琐一些,但可以集中监控所有数据的变化,直接操作Store数据是无法进行监控的

下图通过devtools工具监控

在这里插入图片描述

2 .2 .1 Mutation函数基本语法使用

在mutations中定义函数,如下:

 mutations: {    
      // 自增    
      add(state) {      
      state.count++    
      }  
  }
  • 定义的函数会有一个默认参数state,这个就是存储在Store中的state对象。
2 .2 .1 .1方式一
  • 在组件中,通过this.$store.commit(方法名)完成触发,如下:
mutations: {    
      // 自增    
      add(state) {      
      state.count++    
      }  
  }
2 .2 .1 .2 方式二
  • 在组件中导入mapMutations函数
import { mapMutations } from 'vuex'
  • 通过导入的mapMutations函数,将需要的mutations函数映射为当前组件的methods方法:
  methods: {
      ...mapMutations(["increment", "decrement"]),
      //对象写法
      ...mapMutations({
        add: "increment"
      })
    },

2 .2 .2 Mutation传递参数

  • 在通过mutation更新数据的时候,有时候需携带一些额外的参数,此处,参数被成为mutation的载荷Payload。
    • 如果仅有一个参数时,那payload对应的就是这个参数值,

在这里插入图片描述

  • 如果是多参数的话,那就会以对象的形式传递,此时的payload是一个对象,可以从对象中取出相关的数据。
    • mutations中定义函数时,同样可以接收参数,示例如下:
mutations: {
    // 自增
    add(state) {
      state.count++
    },
    // 带参数
    addNum(state, payload) {
      state.count += payload.number
    }
  }

App.vue组件调用

methods: {
  add() {
    //   this.$store.state.count++;
    this.$store.commit("add");
  },
  addNum() {
    this.$store.commit("addNum", {
      number: 10
    });
  }
}

2 .2 .3Mutation常量类型

  • 在mutation中, 我们定义了很多事件类型(也就是其中的方法名称),当项目越来越大时,Vuex管理的状态越来越多,需要更新状态的情况也越来越多,也就意味着Mutation中的方法越来越多。
  • 当方法过多,使用者需要花费大量时间精力去记住这些方法,甚至多个文件间来回切换,查看方法名称,也存在拷贝或拼写错误的情况。

解决方案

  • 创建mutation-types.js文件,在其中定义常量
  • 定义常量时, 可以使用ES2015中的风格, 使用一个常量来作为函数的名称
  • 使用处引入文件即可
    在这里插入图片描述
    在store/index.js中引入并使用:
import Vue from 'vue'
import Vuex from 'vuex'
import * as types from './mutation-type'
 
Vue.use(Vuex)
 
export default new Vuex.Store({
  state: {
    count: 0,
    user: {
      name: '旺财',
      age: 12
    }
  },
  mutations: {
    // 自增
    [types.ADD_NUM](state) {
      state.count++
    },
}

在组件中,引入并调用:

<script>
import { ADD_NUM } from "../store/mutation-type";
export default {
  methods: {
    add() {
      this.$store.commit(ADD_NUM);
      //   this.addAsync();
      //   this.$store.state.count++;
      //   this.$store.commit("add");
    }
  }
};
</script>

2 .3 Action使用

  • Action类似于Mutation,但是是用于处理异步任务的,比如网络请求等
  • 如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但在Action中还是要通过触发Mutation的方式间接变更数据。

参数context

  • 在actions中定义的方法,都会有默认值context

  • context是和store对象具有相同方法和属性的对象

  • 可以通过context进行commit相关操作,可以获取context.state数据

2 .3 .1 Actons使用方式

注意点

  • 在 action 中,不能直接修改 state 中的数据

  • 必须通过 context.commit() 触发某个 mutation 才行

使用方式一 :

  • 在index.js中,添加actions及对应的方法:
export default new Vuex.Store({
  state: {
    count: 0
  },
 //只有 mutations 中定义的函数,才有权力修改 state 中的数据
  mutations: {
    // 自增
    add(state) {
      state.count++
    }
  },
  actions: {
    addAsync(context) {
      setTimeout(() => {
      //在 action 中,不能直接修改 state 中的数据
      //必须通过 context.commit() 触发某个 mutation 才行
        context.commit('add')
      }, 1000);
    }
  }
})
  • 在组件中调用:dispatch派发
<script>
export default {
  methods: {
    addNumSync(){
        // dispatch函数 专门用于触发 Action
        this.$store.dispatch('addAsync')
    }
  }
};
</script>
2 .3 .1 .2 使用方式二
  • 在组件中,导入mapActions函数
import { mapActions } from 'vuex'
  • 通过刚才导入的mapActions函数,将需要的actions函数映射为当前组件的methods方法:
<script>
import { mapActions } from "vuex";
export default {
  methods: {
    ...mapActions(["addAsync"]),
    add() {Î
        this.addAsync()
    },
}
2 .3 .1 .2 使用方式三
  • 在导入mapActions后,可以直接将指定方法绑定在@click事件上。
...mapActions(["addAsync"]),
---------------------------
 <button @click="addAsync">+1(异步)</button>

2 .3 .2 Actions携带参数

  • index.js的actions中,增加携带参数方法,如下:
export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    // 带参数
    addNum(state, payload) {
      state.count += payload.number
    }
  },
  actions: {
    addAsyncParams(context, payload) {
      setTimeout(() => {
        context.commit('addNum', payload)
      }, 1000);
    }
  }
})
  • 在组件中,调用如下:
methods: {
    addNumSyncParams() {
      this.$store.dispatch("addAsyncParams", {
        number: 100
      });
    }
  }

2 .3 .3 Actions与Promise结合

Promise经常用于异步操作,在Action中,可以将异步操作放在Promise中,并且在成功或失败后,调用对应的resolve或reject。

  • 在store/index.js中,为actions添加异步方法:
actions: {
    loadUserInfo(context){
      return new Promise((resolve)=>{
        setTimeout(() => {
          context.commit('add')
          resolve()
        }, 2000);
      })
    }
  }
  • 在组件中调用,如下:
methods: {
    addPromise() {
      this.$store.dispatch("loadUserInfo").then(res => {
        console.log("done");
      });
    }
}

2 .4 Getters的使用

  • Getters用于对Store中的数据进行加工处理形成新的数据,类似于Vue中的计算属性
  • Store中数据发生变化,Getters的数据也会跟随变化

2 .4 .1使用方式一

  • 在index.js中定义getter
//定义 Getter
const store = new Vuex.Store({
    state:{
    count: 0
    },
    getters:{
        showNum(state){
          return '当前Count值为:['+state.count']'
        }
      }
})
  • 在组件中使用:
<h3>{{ this.$store.getters.showNum }}</h3>

2 .4 .2 使用方式二

  • 在组件中,导入mapGetters函数
import { mapGetters } from 'vuex'
  • 通过刚才导入的mapGetters函数,将需要的getters函数映射为当前组件的computed方法:
 computed: {
    ...mapGetters(["showNum"])
  }
  • 使用时,直接调用即可:
<h3>{{ showNum }}</h3>

2 .5 Modules使用

  • Vues使用单一状态树,意味着很多状态都会交给Vuex来管理
  • 当应用变的非常复杂时,Store对象就可能变的相当臃肿
  • 为解决这个问题,Vuex允许我们将store分割成模块(Module),并且每个模块拥有自己的State、Mutation、Actions、Getters等

基本使用

  • 在store目录下,新建文件夹modules,用于存放各个模块的modules文件,此处以moduleA为例。
  • 在modules文件夹中,新建moduleA.js,内部各属性state、mutations等都和之前一致,注释详见代码,示例如下:
export default {
    state: {
        name: '凤凰于飞'
    },
    actions: {
        aUpdateName(context) {
            setTimeout(() => {
                context.commit('updateName', '旺财')
            }, 1000);
        }
    },
    mutations: {
        updateName(state, payload) {
            state.name = payload
        }
    },
    getters: {
        fullName(state) {
            return state.name + '王昭君'
        },
        fullName2(state, getters) {
            // 通过getters调用本组方法
            return getters.fullName + ' 礼拜'
        },
        fullName3(state, getters, rootState) {
            // state代表当前module数据状态,rootState代表根节点数据状态
            return getters.fullName2 + rootState.counter
        }
    }
}

注意 局部状态通过context.state暴露出来,根节点状态则为context.rootState

  • 在store/index.js中引用moduleA,如下:
import Vue from "vue"
import Vuex from "vuex"
 
import moduleA from './modules/moduleA'
 
Vue.use(Vuex)
 
const store = new Vuex.Store({
    modules: {
        a: moduleA
    }
})
 
export default store
  • 这样就通过分模块完成了对状态管理的模块化拆分。

2 .5 .1 访问模块中的数据

  • 访问模块中的数据,要加上模块名
  获取数据项:  {{$store.state.模块名.数据项名}}
  获取getters: {{$store.getters['模块名/getters名']}}

在这里插入图片描述

在这里插入图片描述

  • 访问模块中的mutations/actions:

    • 如果namespaced为true,则需要额外去补充模块名
    • 如果namespaced为false,则不需要额外补充模块名
    $store.commit('mutations名')        // namespaced为false
    $store.commit('模块名/mutations名')  // namespaced为true
    

2 .5 .2 利用Modules对项目进行优化

注意 如果项目非常复杂,除了分模块划分外,还可以将主模块的actions、mutations、getters等分别独立出去,拆分成单独的js文件,分别通过export导出,然后再index.js中导入使用。

  • 示例: 分别将主模块的actions、mutations、getters独立成js文件并导出,以actions.js为例,
export default{
    aUpdateInfo(context, payload) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                context.commit('updateInfo')
                resolve()
            }, 1000);
        })
    }
}
  • 在store/index.js中,引入并使用,如下:
import Vue from "vue"
import Vuex from "vuex"
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'
 
 
Vue.use(Vuex)
 
const state = {
    counter: 1000,
    students: [
        { id: 1, name: '旺财', age: 12 },
        { id: 2, name: '小强', age: 31 },
        { id: 3, name: '大明', age: 45 },
        { id: 4, name: '狗蛋', age: 78 }
    ],
    info: {
        name: 'keko'
    }
}
 
const store = new Vuex.Store({
    state,
    mutations,
    getters,
    actions,
    modules: {
        a: moduleA
    }
})
 
export default store

模块项目图
在这里插入图片描述
##2. 6 辅助函数使用汇总

如何使用全局state
  • 直接使用: this.$store.state.xxx;

  • map辅助函数:

    computed: { 
      ...mapState(['xxx']), 
      ...mapState({'新名字': 'xxx'})
    }
    
如何使用modules中的state
  • 直接使用: this.$store.state.模块名.xxx;

  • map辅助函数:

    computed: { 
      ...mapState('模块名', ['xxx']), 
      ...mapState('模块名', {'新名字': 'xxx'})
    }
    
如何使用全局getters
  • 直接使用:this.$store.getters.xxx

  • map辅助函数:

    computed: { 
      ...mapGetters(['xxx']), 
      ...mapGetters({'新名字': 'xxx'})
    }
    
如何使用modules中的getters
  • 直接使用: this.$store.getters.模块名.xxx

  • map辅助函数:

    computed: { 
      ...mapGetters('模块名', ['xxx']), 
      ...mapGetters('模块名',{'新名字': 'xxx'})
    }
    
如何使用全局mutations
  • 直接使用:this.$store.commit('mutation名', 参数)

  • map辅助函数:

    methods: { 
      ...mapMutations(['mutation名']), 
      ...mapMutations({'新名字': 'mutation名'})
    }
    
如何使用modules中的mutations(namespaced:true)
  • 直接使用: this.$store.commit('模块名/mutation名', 参数)

  • map辅助函数:

    methods: { 
      ...mapMutations('模块名', ['xxx']), 
      ...mapMutations('模块名',{'新名字': 'xxx'})
    }
    
如何使用全局actions
  • 直接使用:this.$store.dispatch('action名', 参数)

  • map辅助函数:

    methods: { 
      ...mapActions(['actions名']), 
      ...mapActions({'新名字': 'actions名'})
    }
    
如何使用modules中的actions(namespaced:true)
  • 直接使用: this.$store.dispatch('模块名/action名', 参数)

  • map辅助函数:

    methods: { 
      ...mapActions('模块名', ['xxx']), 
      ...mapActions('模块名',{'新名字': 'xxx'})
    }
    

3 .Vuex核心概念(CPA)

注意点

  • setup没有this
    • 我们知道vue3的setup函数中是没有this的,就算传了context参数,打印出来也没有相关属性
    • 但是我们可以直接从vuex 4.X中解构出useStore方法,就可以在setup中使用vuex的相关函数了

基本使用参考代码

<template>
  <div>
    <h2>{{ $store.state.count }}</h2>
    <button @click="plusCount">点击</button>
  </div>
</template>

<script>
import { useStore } from "vuex";

export default {
  setup(props, context) {
    const store = useStore(); // 使用useStore方法
    console.log(store);

    function plusCount() {
      store.commit("increaseCount");
    }
    return { plusCount };
  },
};
</script>

3 .1. state的使用

导入函数

 import { mapState, useStore } from 'vuex'
 import { computed } from 'vue'

基本使用

 setup() {
      const store = useStore()
      const sCounter = computed(() => store.state.counter)
      //必须return
      return {
        sCounter,
      }
    }

3 .1 .1封装函数的方式使用

创建useStart.js封装函数

import { computed } from 'vue'
import { mapState, useStore } from 'vuex'

export function useState(mapper) {
  // 拿到store独享
  const store = useStore();

  // 获取到对应的对象的functions: {name: function, age: function}
  const storeStateFns = mapState(mapper);

  // 对数据进行转换
  const storeState = {};
  // 抽取key进行遍历
  Object.keys(storeStateFns).forEach((fnKey) => {
    //  把key给storeStateFns函数=>并绑定this
    const fn = storeStateFns[fnKey].bind({ $store: store });
    // 函数给计算属性并赋值给storeState对象
    storeState[fnKey] = computed(fn);
  });

  return storeState;
}
  • 在组件中进行使用
import { useState } from '../hooks/useState'

  export default {
    setup() {
      const storeState = useState(["counter", "name", "age", "height"])
      const storeState2 = useState({
        sCounter: state => state.counter,
        sName: state => state.name
      })

      return {
        ...storeState,
        ...storeState2
      }
    }
  }
  • 展示方式
<h2>{{counter}}</h2>
<h2>{{name}}</h2>

3 .2 Getters的基本使用

  • 某些属性我们可能需要变化后在使用,这个时候可以使用getters:(相当于computed属性)
    在这里插入图片描述
    在这里插入图片描述

3 .2 .1 getters第二个参数与返回值

  • getters可以接收第二个参数:
    在这里插入图片描述

  • getters中的函数本身,可以返回一个函数,那么在使用的地方相当于可以调用这个函数:
    在这里插入图片描述
    index.js中state与Getter代码

state() {
    return {
      counter: 100,
      name: "why",
      age: 18,
      height: 1.88,
      books: [
        { name: "深入Vuejs", price: 200, count: 3 },
        { name: "深入Webpack", price: 240, count: 5 },
        { name: "深入React", price: 130, count: 1 },
        { name: "深入Node", price: 220, count: 2 },
      ],
      discount: 0.6,
      banners: []
    };
  },
  getters: {
    totalPrice(state, getters) {
      let totalPrice = 0
      for (const book of state.books) {
        totalPrice += book.count * book.price
      }
      return totalPrice * getters.currentDiscount
    },
    currentDiscount(state) {
      return state.discount * 0.9
    },
    totalPriceCountGreaterN(state, getters) {
      return function(n) {
        let totalPrice = 0
        for (const book of state.books) {
          if (book.count > n) {
            totalPrice += book.count * book.price
          }
        }
        return totalPrice * getters.currentDiscount
      }
    },
  • 组件代码
<h2>总价值: {{ $store.getters.totalPrice }}</h2>
<h2>总价值: {{ $store.getters.totalPriceCountGreaterN(1) }}</h2>

3 .2 .2 封装函数的方式使用

创建useGetters.js

import { computed } from 'vue'
import { mapGetters, useStore } from 'vuex'

export function useGetters(mapper) {
  // 拿到store独享
  const store = useStore()

  // 获取到对应的对象的functions: {name: function, age: function}
  const storeStateFns = mapGetters(mapper)

  // 对数据进行转换
  const storeState = {}
  Object.keys(storeStateFns).forEach(fnKey => {
    const fn = storeStateFns[fnKey].bind({$store: store})
    storeState[fnKey] = computed(fn)
  })

  return storeState
}
  • 在组件中的使用
<template>
  <h2>{{ nameInfo }}</h2>
  <h2>{{ ageInfo }}</h2>
  <h2>{{ heightInfo }}</h2>
</template>
import { useGetters } from '../hooks/useGetters'

  export default {
    computed: {

    },
    setup() {
      const storeGetters = useGetters(["nameInfo", "ageInfo", "heightInfo"])
      return {
        ...storeGetters
      }
    }
  }

3 .Mutation的使用

  • 提交载荷(Payload)
  • 对象风格的提交方式
  • 使用常量替代 Mutation 事件类型
  • Mutation 必须是同步函数
  • 在组件中提交 Mutation

Mutation的使用核心参考官网

4 .Action的使用

4 .1Action的异步使用

  • index.js中为Actions添加异步方法
getHomeMultidata(context) {
      return new Promise((resolve, reject) => {
        axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
          context.commit("addBannerData", res.data.data.banner.list)
          resolve({name: "xiazhan", age: 18})
        }).catch(err => {
          reject(err)
        })
      })
    }
  • 在组件中使用
setup() {
      const store = useStore()

      onMounted(() => {
        const promise = store.dispatch("getHomeMultidata")
        promise.then(res => {
          console.log(res)
        }).catch(err => {
          console.log(err)
        })
      })
    }

5 .Mudule的使用

  • 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,store 对象就有可能变得相当臃肿;
  • 为了解决以上问题,Vuex 允许我们将store 分割成模块(module);
  • 每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块;
    在这里插入图片描述
    在这里插入图片描述

5 .1module的命名空间

  • 默认情况下,模块内部的action和mutation仍然是注册在全局的命名空间中的:
    • 这样使得多个模块能够对同一个action 或mutation 作出响应;
    • Getter 同样也默认注册在全局命名空间;
  • 如果我们希望模块具有更高的封装度和复用性,可以添加namespaced: true 的方式使其成为带命名空间的模块:
  • 当模块被注册后,它的所有getter、action 及mutation 都会自动根据模块注册的路径调整命名;

在模块module文件夹中创建home.js

const homeModule = {
  // 指定命名空间 =>局部
  namespaced: true,
  state() {
    return {
      homeCounter: 100
    }
  },
  getters: {
    doubleHomeCounter(state, getters, rootState, rootGetters) {
      return state.homeCounter * 2
    },
    otherGetter(state) {
      return 100
    }
  },
  mutations: {
    increment(state) {
      state.homeCounter++
    }
  },
  actions: {
    incrementAction({commit, dispatch, state, rootState, getters, rootGetters}) {
      commit("increment")
      commit("increment", null, {root: true})
    }
  }
}
export default homeModule

在入口文件index.js导入home.js

import { createStore } from "vuex"
import home from './modules/home'
import user from './modules/user'

const store = createStore({
  state() {
    return {
      rootCounter: 100
    }
  },
  getters: {
    doubleRootCounter(state) {
      return state.rootCounter * 2
    }
  },
  mutations: {
    increment(state) {
      state.rootCounter++
    }
  },
  modules: {
    home,
    user
  }
});
export default store;

在组件中访问home.js' 中的counte和action的数据

<template>
  <div>
  //[查找规则]
    <h2>{{ $store.getters["home/doubleHomeCounter"] }}</h2>

    <button @click="homeIncrement">home+1</button>
    <button @click="homeIncrementAction">home+1</button>
  </div>
</template>

<script>
  export default {
    methods: {
      homeIncrement() {
        this.$store.commit("home/increment")
      },
      homeIncrementAction() {
        this.$store.dispatch("home/incrementAction")
      }
    }
  }
</script>
<style scoped>
</style>

5 .2module修改或派发根组件

  • 如果要在action中修改root中的state,可以使用:

在这里插入图片描述
参考代码

 actions: {
    incrementAction({commit, dispatch, state, rootState, getters, rootGetters}) {
      commit("increment")
      commit("increment", null, {root: true})
    }
  }

5 .3module的辅助函数

  • 方式一:通过完整的模块空间名称来查找;
    在这里插入图片描述
    -方式二: 第一个参数传入模块空间名称,后面写上要使用的属性;
    在这里插入图片描述
  • 方式三:通过createNamespacedHelpers 生成一个模块的辅助函数;
    在这里插入图片描述
    setup中的使用
 setup() {
      // {homeCounter: function}
      const state = useState(["rootCounter"])
      const rootGetters = useGetters(["doubleRootCounter"])
      const getters = useGetters("home", ["doubleHomeCounter"])

      const mutations = mapMutations(["increment"])
      const actions = mapActions(["incrementAction"])

      return {
        ...state,
        ...getters,
        ...rootGetters,
        ...mutations,
        ...actions
      }
    }

4 .面试题型

4 .1项目结构

Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

  1. 应用层级的状态应该集中到单个 store 对象中。
  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  3. 异步逻辑都应该封装到 action 里面。

只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。

对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:

在这里插入图片描述

4 .2 vuex的五个核心

一、Vuex的五个核心概念:state、getters、mutations、actions、modules
1、state: vuex的基本数据,用来存储变量
2、getters: 从基本数据(state)派生的数据,相当于state的计算属性;
3、mutations: 提交更新数据的方法,必须是同步的(如果需要异步使用action)。每个mution 都有一个字符串的事件类型(type)和一个回调函数(handler)。
回调函数就是我们实际进行状态更改的地方,并且它会接受 state作为第一个参数,提交载荷作为第二个参数。
4、action: 和mution的功能大致相同,不同之处在于 ①Action提交的是mution,而不是直接变更状态,②Action可以包含任意异步操作。
5、modules: 模块化vuex,可以让每一个模块拥有自己的 state、mutation、action、 getters,使得结构非常清晰,方便管理。

图解
在这里插入图片描述
参考: vue中使用vuex(超详细)
vuex基础解析
vuex官网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值