vuex的使用经验

vuex使用经验

前言

因为在项目中使用vuex的关系,最近重新在慕课网上学习了这个课程。对它的了解又进一步。

vuex就是一个状态管理的仓库,只要是vue项目的同一个页面的所有组件,都可以对这个仓库进行的状态进行存储,修改或者读取。不是同一个页面的话,可以通过浏览器的cookie,localStorage,sessionStorage进行桥连,就是在切换路由的时候,判断localStorage,或者sessionStorage是否存有值,有的话,就拿里面的值给vuex里面对应的State名;每次存Vuex里面的值时,记得给localStorage存一份。当然在这里不是每一个State的值都要备份到Storage里面去。需要桥连多个页面的那些State才需要,这样子可以写少代码量。

State

State是状态库,它就好像一个数据库,存放数据的,一个字段对应一个数值。

State看起来很简单,其实不然,他有个高级的用法。像我在上一家公司录入东西时,新增页面5种类型的该东西,编辑页面可以有更多种,如果我只是定义一个status的值,解决不了我的问题。那就把他写成一个对象,给该对象添加根据类型值的属性和值,在另外一个组件监听该状态下的属性值,做点什么。

其实这里uniqueFlag要找对,找不对的话,程序会出问题。新增页面SH类型,编辑页面找SH类型加SH编号。一开始无论新增/编辑页面我只找SH类型,这样子是不对的,比如多开2个编辑页面的话同时进行会出问题。大多数测试测不到这个问题是因为他们习惯只开一个编辑页面。

实现如下:

//一、定义
 state: {
        secIndustry: '',//第二行业类型
    },
    mutations: {
        setSecIndustryAsyc:(state,data) => {
            state.secIndustry = {
                ...state.secIndustry,
                ...data,
            }; 
        },
    },
}

//二、修改值
let newObj = {};
let uniqueFlag = ''; //唯一标识
newObj['secIndustry'+ uniqueFlag] = secIndustry;
store.dispatch('setSecIndustry', newObj);  //设置第二行业分类

//三、//监听store里面的状态secIndustry下的某个属性变化
let uniqueFlag = 'xxx'; //唯一标识
computed: {
    ...mapGetters(['secIndustry'])
},
watch: {
    //"secIndustry." + uniqueFlag: function(newV,oldV){ 
    //本来我想使用.属性的方式来监听的,发现拼接不上,没法实现,只好手写如下
    //这样子就处理好了
    "secIndustry": function(newV,oldV){
        if(newV[uniqueFlag] != oldV[uniqueFlag]){
            //干点什么
        }
    }
},

mutations

vuex不是直接去该state里面的值,而是通过mutations或者actions。这样的好处是为了记录State的每一次的修改活动,方便调试和状态回滚。这个回滚是啥,有什么好处,不太懂,在项目中没有用过。 mutations里面是一堆的方法,方法的第一个参数是state。如果有第二参数,那就是调用传入该方法的参数。

mutations只要是同步修改,增加,减少state的值。在项目中主要都是在定义好state的值,mutations修改操作。

定义:

mutations:{
    //es6语法,等同edit:funcion(){...}
    edit(state,payload){
        //state.name = 'jack'
        state.name = payload.xxx;
    }
}

在同一个页面的任意一个vue里面,使用:(原来我一直以为只能在actions里面使用)

this.$store.commit('edit');

this.$store.commit('edit',15)

this.$store.commit('edit',{age:15,sex:'男'})

//或者正规一些的方式
this.$store.commit({
    type:'edit',
    payload:{
        age:15,
        sex:'男'
    }
})

或者在actions里面使用

actions:{
    aEdit(context,payload){
        setTimeout(()=>{
            context.commit('edit',payload)
        },2000)
    },
    
    //或者actions里面简单的写法 
    aEdit({commit},payload){
        setTimeout(()=>{
            commit('edit',payload)
        },2000)
    }
}

在这里想说说这个接参数使用{}方式的好处。可以减少代码的书写,我们一般会知道传过来的对象里面有哪些,如果使用{}的方式接收参数,这样子拿值时就少写一层名称。就好比上面那些代码可以少写context。简洁了。我们在定义工具类的时候,大可以使用这种方式来简化单词量。

/**
 * @desc 转换时间 
 * @param paraObj 对象
 *              DetailsVO  对象
 *              key  目标键
 * @returns newObj
 *              xxxx1时间值
 *              String文字描述
 */
export function convertTime({DetailsVO,key}) {
    let momentObj;
    let newObj = {};
    if (DetailsVO[key] == '9999-12-31') {   //该项为长期有效
        momentObj = null;
        newObj[key+'1'] = momentObj;  //时间
        newObj['timePlaceHolderString'] = '长期有效'
        //console.log('==================================')
    }else if(DetailsVO[key] != null && DetailsVO[key] != ''){
        momentObj = moment(DetailsVO[key]  + '', 'YYYY-MM-DD');
        newObj[key+'1'] = momentObj;  //时间
    }
    return newObj;
}

actions

因为在大多数情况下,我们写代码的处理方式是异步(api,setTimeout),不是同步的。这时候需要在actions里面。如果硬是把异步的操作写在mucation,state里面的状态会发生混乱,就是说页面的值变化,state的值还是原来的。

定义:

actions:{
    aEdit(context,payload){
        setTimeout(()=>{
            context.commit('edit',payload)
        },2000)
    }
}

使用:

this.$store.dispatch('aEdit',{age:15})

actions还有一个高级的用法,因为它是异步操作,我们可以使用Promise来封装之。

//定义
actions:{
    aEdit(context,payload){
        return new Promise((resolve,reject)=>{
            //或者说在这里发送ajax请求
            setTimeout(()=>{
                context.commit('edit',payload)
                resolve()
                //resolve('后台对象')
            },2000)
        })
    }
}

//使用
this.$store.dispatch('aEdit',{age:15}).then((returnObj)=>{
    //做点什么
    //比如拿到后台数据改变本组件的data值;
})

actions和aync await组合使用,可以等待。更高级的写法。

在平时开发中我遇到一个需求是,我需要一个信息采集组件采集多个数据塞到一个数组里面,在其他组件点击该按钮时触发这件事,等数据采集完毕,再拿采集到的数据作为参数去调用其他接口。其实可以这样子做,设置一个state字段,以async wait方式写 actions,在信息采集组件监听该状态的变化,当变化时,做采集数据这个事完了,才去做其他事情。这样子应该就可以解决问题了。 这个需求一句话概括就是改变了state的状态,等待状态修改完毕再做点什么。

//定义
actions:{
    async aEdit(context,payload){
        return new Promise((resolve,reject)=>{
            //或者说在这里发送ajax请求,setTimeOut
            setTimeout(()=>{
                context.commit('edit',payload)
                resolve('ok了')
                //resolve('后台对象')
            },2000)
        })
    }
}
//使用
try {
    let res =  await this.$store.dispatch('aEdit',{age:15})
    if(res === 'ok了'){
        //做点什么
        //这会儿信息采集完,做点其他事情。
    }
}catch(err){

}
})
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

getters

存钱是为了什么,是为了拿钱去用。getters就是拿钱,它最爽。getters和actions的关系就好比小孩和大人,小孩是花钱的。

用官方的话说,getters就是把state里面的状态暴露出去。

//定义
getters:{
    nameInfo(state){
        return "姓名:"+state.name
    },
}

//使用同一页面的Vue文件中
this.$store.getters.fullInfo

modules

当一个项目属于中大型,处理的逻辑多,我们需要频繁的写很多的getters,actions,mutation,states;写很多的时候,维护性和阅读性就低。每一个功能的都有自己对应的getters,actions,mutations,按功能划分的话,代码的维护性就上去,modules就是为了这个而来的。

辅助函数(四件)

辅助函数就是为了让开发者快速简洁使用Vuex。它是利用对象展开运算符,做了映射处理,这样子就不用使用 store.commit store.dispatch store.getters,这些又长又臭的语句。

定义很简单的,getters和state搞到computed那里,mapMutations和mapActions推到methods那里。 为啥不把getters等搞到data那里?因为在业务中需要追踪state状态的值,实时更新,data只能拿到某个时刻的状态值。

辅助函数给我的感觉是真香。

computed: {
     // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ]),
     // 使用对象展开运算符将 state 混入 computed 对象中
     // 为啥有了getters还要State,其实是一样的,mapState显得有点冗余,用getters也是可以的。
    ...mapState([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
},

methods:{
    ...mapMutations([
      'increment' // 映射 this.increment() 为 this.$store.commit('increment')
    ]),
    ...mapMutations({
      add: 'increment' // 映射 this.add() 为 this.$store.commit('increment')
    }),

     ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
}, 

使用:

//需要传值就给个参数,否则直接调用。
this.increment({ amount: 10 }) 或 this.add({ amount: 10 })
this.increment() 或 this.add()

不建议开始接触Vuex就使用辅助函数,应该使用基本写法一小段时间之后,对Vuex有了了解,再使用辅助函数。

posted @ 2020-07-24 09:12  是豆腐啊  阅读(220)  评论(0编辑  收藏  举报