Vuex常见问题

289 阅读2分钟

Vuex常见问题

如果你分手了就去西藏 可以疗伤 如果你单身就去丽江 可以艳遇 如果你喜欢我 就来温州鞋厂 可以跟我一起打工 早上好 打工人

如何引用Vuex

  • 先安装依赖npm install vuex --save
  • 在项目目录src中建立store文件夹
  • 在store文件夹下新建index.js文件,写入
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
//创建vuex实例对象
const store = new Vuex.Store({
    state:{},
    getters:{},
    mutations:{},
    actions:{}
})
export default store;
  • 然后在main.js文件中引入Vuex,如下
import Vue from 'vue';
import App from './App.vue';
import store from './store';
const vm = new Vue({
    store:store,
    render: h => h(App)
}).$mount('#app')

state

Vuex的状态储存在state中,而改变Vuex中的状态的唯一途径就是显示地提交(commit)mutation

注意:因为对象是引用类型,复制后改变属性还是会影响原始数据,这样会改变state里面的状态,是不允许的,所以先使用深克隆复制对象,再修改

  • Vuex的state状态如何在组件中批量使用
//利用mapState辅助函数,利用对象展示运算符将state混入到computed对象中
import {mapState} from 'vuex'
export default{
    computed:{
        ...mapState(['price','number'])
    }
}
  • 在v-model上怎么使用state的值
<input v-model="message">
// ...
computed: {
    message: {
        get () {
            return this.$store.state.message
        },
        set (value) {
            this.$store.commit('updateMessage', value)
        }
    }
}

getter

  • Vuex的getters状态如何在组件中批量使用---取别名使用
//使用mapGetters辅助函数,利用对象展示运算符将getter混入到computed对象中
import {mapGetters} from 'vuex'
export default{
    computed:{
        ...mapGetters(['total','discountTotal'])
    }
}
--------------取别名使用----------------
//使用mapGetters辅助函数,利用对象展示运算符将getter混入到computed对象中
import {mapGetters} from 'vuex'
export default{
    computed:{
        ...mapGatters({
            myTotal:'total',
            myDiscountTotal:'discountTotal'
        })
    }
}
  • Vuex中要从state派生一些状态出来,且多个组件使用它
//使用getter属性,相当于Vue中的计算属性computed,只有原状态改变,派生状态才会改变
//gerrer接受两个参数,第一个state,第二个是getters(可以用来访问其他getter)
const store = new Vuex.Store({
    state: {
        price: 10,
        number: 10,
        discount: 0.7,
    },
    getters: {
        total: state => {
            return state.price * state.number
        },
        discountTotal: (state, getters) => {
            return state.discount * getters.total
        }
    },
});
//然后在组件中可以用计算属性computed通过this.$store.getters.total这样来访问这些派生状态
computed: {
    total() {
        return this.$store.getters.total
    },
    discountTotal() {
        return this.$store.getters.discountTotal
    }
}
  • 怎么通过getter来实现在组件内可以通过特定条件来获取state的状态
//通过让getter返回一个函数来实现给getter传参,然后通过参数来判断,从而获取state中满足要求的状态
const store = new Vuex.Store({
    state:{
        todos:[
            {id:1,text:'哈哈',done:true},
            {id:2,text:'嘿嘿',done:false}
        ]
    },
    getters:{
        getTodoById:(state)=>(id)=>{
            return state.todos.find(r=>r.id === id)
        }
    }
});
//然后在组件中可以用计算属性computed通过this.$store.getters.getTodoById(2)这样来访问这些派生状态
computed: {
    getTodoById() {
        return this.$store.getters.getTodoById
    }
},
mounted(){
    console.log(this.getTodoById(2).done); //false
}

mutation

mutation必须是同步函数

  • 在Vuex的state中有个状态number表示货物数量,在组件中改变它的状态
//首先要在mutations中注册一个mutation
const store = new Vuex.Store({
    state:{number:10},
    mutations:{
        SET_NUMBER(state,data){
            state.number = data;
        }
    }
});
//在组件中使用this.$store.commit()提交mutation,改变number的值
this.$store.commit('SET_NUMBER',123)
  • 在组件中多次提交同一个mutation,怎么写使用更方便
//使用mapMutations辅助函数,在组件的methods中这么使用
import {mapMutations} from 'vuex'
export default{
    methods:{
        ...mapMutations({
            setNumber:'SET_NUMBER'
        })
    }
}
//调用--->相当于调用this.$store.commit('SET_NUMBER',123)
this.setNumber(123)

action

action提交的是mutation,而不是直接更改状态。mutation可以直接更改state的状态; action可以包含任意异步操作。mutation只能是同步操作。

action是用this.$store.dispatch('Action_Name',data)来提交。mutation是用this.$store.commit('SET_NUMBER',123)来提交。

mutation的第一个参数是state,而action的第一个参数是context。他俩的第二个参数都可以接收外部提交时传来的参数。

  • 在组件中多次提交同一个action,怎么写使用更方便
//使用mapActions辅助函数,在组件的methods中这么使用
import {mapActions} from 'vuex'
export default{
    methods:{
        ...mapActions({
            setNumber:'SET_NUMBER'
        })
    }
}
//调用--->相当于调用this.$store.dispatch('SET_NUMBER',123)
this.setNumber(123)

-Vuex中的action通常是异步的,那么如何知道action什么时候结束

//在action函数中返回Promise,然后再提交时候用then处理
actions:{
    SET_NUMBER_A({commit},data){
        return new Promise((resolve,reject) =>{
            setTimeout(() =>{
                commit('SET_NUMBER',10);
                resolve();
            },2000)
        })
    }
}

this.$store.dispatch('SET_NUMBER_A').then(() => {
  // ...
})

module

项目使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。所以将 store 分割成模块(module)。每个模块拥有自己的 state、mutations、actions、getters,甚至是嵌套子模块,从上至下进行同样方式的分割。

//在module文件新建moduleA.js和moduleB.js文件。在文件中写入
const state = {...}
const getters = {...}
const mutations = {...}
const actions = {...}
export default{
    state,
    getters,
    mutations,
    actions
}
//然后再index.js引入模块
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
import moduleA from './module/moduleA'
import moduleB from './module/moduleB'
const store = new Vuex.Store({
    modules:{
        moduleA,
        moduleB
    }
})
export default store

  • 在模块中,getter和mutation接收的第一个参数state是全局的还是模块的?
第一个参数state是模块的state,也就是局部的state。
  • 在模块中,组件怎么访问getter和state,怎么提交mutation和action
直接通过this.$store.gettersthis.$store.state来访问模块中的getter和state
直接通过this.$store.commit('mutationA',data)提交模块中的mutation
直接通过this.$store.dispatch('actionA',data)提交模块中的action
  • 在模块中,getter和mutation和action如何访问全局的state和getter?
在mutation中不可以访问全局的state和getter,只能访问到局部的state
在action中第一个参数context中的context.rootState可以访问全局的state,参数context.rootGetters可以访问全局的getter
在getter中可以通过第三个参数rootState访问到全局的state,可以通过第四个参数rootGetters访问到全局的getter

Vuex模块的命名空间

默认情况下,模块内部的action、mutation和getter是注册在全局命名空间,如果多个模块中action、mutation的命名是一样的,那么提交mutation、action时,将会触发所有模块中命名相同的mutation、action。

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

export default{
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}
  • 怎么在带命名空间的模块内注册全局的action?
actions: {
    actionA: {
        root: true,
        handler (context, data) { ... }
    }
  }
  • 怎么在带命名空间的模块内提交全局的mutation和action?
//将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。
this.$store.dispatch('actionA', null, { root: true })
this.$store.commit('mutationA', null, { root: true })
  • 组件中怎么提交modules中的带命名空间的moduleA中的mutationA?
this.$store.commit('moduleA/mutationA',data)
  • 怎么使用mapState,mapGetters,mapActions和mapMutations这些函数来绑定带命名空间的模块?
//首先使用createNamespacedHelpers创建基于某个命名空间辅助函数
import { createNamespacedHelpers } from 'vuex';
const { mapState, mapActions } = createNamespacedHelpers('moduleA');
export default {
    computed: {
        // 在 `module/moduleA` 中查找
        ...mapState({
            a: state => state.a,
            b: state => state.b
        })
    },
    methods: {
        // 在 `module/moduleA` 中查找
        ...mapActions([
            'actionA',
            'actionB'
        ])
    }
}