浅析如何保证vuex中的state动态添加属性的响应式及解决deep watch / computed监听vuex state对象属性变化不生效的问题

一、vuex 的 state 如何保证其响应式

  vuex 的 store对象的 state 是响应式的,凡是预先在 state 中定义的状态,都会被加入到响应式系统中,当状态发生了变化,所有引用状态的 vue 文件的 template 都会随之发生变化,做到响应式的功能。

  但是其前提是:提前定义好的会被加入到响应式系统中,那后面追加的属性或对象能不能加入到响应式系统中呢?

  答案是:不能,但是,如果按照指定的方式来添加和删除属性,是可以做到响应式的。

  比如现在我要添加一个新属性 height,用两种方式添加,如下:

1、方式1:此种方式能添加 state 中对象的属性,但无法加入到响应式系统中,即页面上不会显示出来,实际上确实存在了这个属性

mutations: {
  addheight(state){
    state.stus[0]['height'] = 168
  }
}

2、方式2:此方式可以让属性加入到响应式系统中

mutations: {
  addheight(state){
    Vue.set(state.stus[1],'height',178) //参数一为对象,参数二为key,参数为value
  }
}

3、方式3:用新对象给旧对象重新赋值(下面会介绍到)

4、说完添加属性,再说下删除吧,想要删除属性并加入响应式系统,如下方式:

mutations: {
  delheight(state){
    Vue.delete(state.stus[1],'height') //参数一为对象,参数二是key
  }
}

5、总结:

(1)Vuex 的 store 对象中的 state 是响应式的,当 state 中的数据发生改变时,vue 组件会自动更新。

(2)但是它有一个前提条件,与我们之前了解的响应式前提是一致的,就是需要:提前在 state 中定义好所需的初始化属性。动态添加的属性是不能响应式的。

(3)如何保证动态添加的属性的响应式呢 - 有一下两种方式

  方式一:使用 Vue.set(obj, key, value)

  方式二:使用新对象给旧对象重新赋值

(4)在state删除已经存在的属性,使用 delete + 属性满足不了响应式,必须这样使用:Vue.delete(obj, 属性名)

二、解决 computed 监听 vuex 中 state 对象属性不生效的问题

  首先我们需要了解一个前提基础:

computed 属性监听对象时候,若对象的引用地址未改变,那么computed将不会检测到。

比如object中的某个key对应的value发生了变化,computed检测不出来

// 原写法
export default {
    namespaced: true,
    state: {
        info:{
             other: {}
        }
    },
    mutations: {
        addInformation(state,info){
            let data = Object.assign(state.info, info);
            //此时 state.info 的值改变了,但是引用地址没变
            state.shareInformation = data;
        },
    }
}

  使用 Object.assign() 的目标对象仍然是 state.info ,所以虽然其值变了,但是引用地址是没变的,所以 computed 检测不到。

// 正确写法
addInformation(state,info){
  //创建一个新的对象,将state.info,Info 对象复制到新对象中
  let data = Object.assign({},state.info,info);
  //将 state.info 指向新对象的引用地址
  state.info = data;
},

  使用 Object.assign() 的目标对象是个空对象,将 2 个源对象 state.info、info 的内容复制到新对象上 ,所以其值变了,引用地址也变了。这样 computed 才可以检测到。

三、vue 关于 deep watch 监听不到 vuex state 对象变化的的问题

  简而言之,如果 vuex state 中是一个空对象 {},那么监听就会有问题,必须得有提前定义好的初始化属性才可以保证监听。那么如果无法确定动态添加属性的 key 是啥,怎么办呢?先给出解决方案:

// 简易拷贝
let _reply = JSON.parse(JSON.stringify(state.reply))
// 加入动态属性 orderId 是变化的
_reply[orderId] = data.orderId
// 更新,只能这样一波骚操作才能让computed和watch监听到。 state.reply = _reply

  具体原因其实跟第二章一样,要保证其引用地址变了才行。

posted @ 2021-11-12 13:40  古兰精  阅读(5130)  评论(0编辑  收藏  举报