Vue.js Vuex:向对象添加动态属性,而不触发现有属性上的观察程序

Vue.js Vuex:向对象添加动态属性,而不触发现有属性上的观察程序,vue.js,vuex,Vue.js,Vuex,我有一个带有对象的Vuex存储: state: { contents: {}, } 其中,我按键动态存储内容: mutations: { updateContent: (state, { id, a, b }) => { Vue.set(state.contents, id, { a, b }); }, } 并让他们使用: getters: { content: (state) => (id) => { if (

我有一个带有对象的Vuex存储:

 state: {
    contents: {},
 }
其中,我按键动态存储内容:

mutations: {
   updateContent: (state, { id, a, b }) => {
       Vue.set(state.contents, id, { a, b });
   },
}
并让他们使用:

getters: {
    content: (state) => (id) => {
        if (id in state.contents) return state.contents[id];
        return [];
    }
}, 
假设我有这样一个组件:

export default {
    props: ["id"],
    computed: {
       myContent() {
          return this.$store.getters.content(this.id)
       }
    },
    // ...
}
如何使用变异添加动态属性而不触发组件中的更改?查看
state.contents的未更改、已存在的属性


另请参见此图。

如果您想查看对象的内部属性,可以使用
深度观察程序

在您的情况下,我假设您正确设置了getter、setter和update方法。您应该将此添加到您的观察者:

// ...
watch:{
  id: {
    deep: true,
    handler(newVal, oldVal){
      console.log("New value and old value: ", newVal, oldVal")
      // ... make your own logic here
    }
  }
}

让我再解释一下上面的代码,当我们想查看Vue中任何对象的内部属性时,我们应该使用
deep
handler
函数来处理每次更改。(请记住,handler不是一个随机名称,它是保留关键字)

我试图通过检查fiddle:,来找出它,我有一个可能的原因导致这种行为

当观察到的对象或其中的属性发生更改时,将更新或访问getter和计算属性。在这种情况下,
content
getter正在“监视”state.contents
store属性,因此每次更新
store.contents
时,调用
content
getter,然后调用计算属性
myContent()
更新其值,并使用
this.update++
增加
updated
数据属性

因此,如果更新了
state.contents
属性,组件将始终更新,即添加一个
新的不相关属性

,Vue(x)似乎无法做到这一点。但是,通过添加一个空的观察者(是的,这是一种攻击),您可以使Vue组件暂时不起作用(基于此)

基本上,我们在对象本身上有一个观察者,在每个属性上都有一个观察者。我们将摧毁目标上的观察者。这样做时,我们必须确保,当一个组件第一次调用getter时,它返回一个被动值,而不是
{}
,因为getter无法再观察到向对象添加新属性的情况。因此,我们在初始化对象时添加了一个
touch
。此函数需要对象的原始观察者在其属性上创建观察者,从而对组件进行一次(但仅一次)不必要的更新:

mutations: {
    updateContent: (state, { id, a, b }) => {
        Vue.set(state.contents, id, { a, b });
    },
    touch: (state, { id }) => {
            if(id in state.contents) return
        if (myObserver === null)
            myObserver = state.contents.__ob__
        state.contents.__ob__ = myObserver
        Vue.set(state.contents, id, {});
        state.contents.__ob__ = new Observer({});
    }
},
可以使用以下方法获得构造函数:

 const Observer = (new Vue()).$data.__ob__.constructor;
每当
id
更改时,我们的组件必须调用
touch

props: ["id"],
watch: {
    i: {
        immediate: true,
        handler() {
            this.$store.commit("touch", { id: this.id })
        }
    }
},
computed: {
    myContent() {
        return this.$store.getters.content(this.id)
    }
},

如中所示,向对象添加新属性不会再触发不必要的更新。

可以使用全局事件总线而不是vuex getter:

const eventBus = new Vue();
组件可以订阅所需的元素:

 watch: {
    id: {
        handler(n, o) {
            if (o) eventBus.$off(o + "", this.onChange);
            eventBus.$on(n + "", this.onChange);
            this.$store.dispatch("request", { id: n });
        },
        immediate: true
    }
},
必须通知组件的更改将使用操作进行调度:

actions: {
    request(_, { id }) {
        eventBus.$emit(id + "", this.getters.content(id));
    },
    updateContent({ commit }, { id, a, b }) {
        commit("updateContent", { id, a, b });
        eventBus.$emit(id + "", { a, b });
    }
}
这样可以精确地控制何时触发更新


.

理论上,这是阻止设置程序,但您也可以只制作一个只监视此属性的计算程序,并将其从vue e外部添加到冻结的对象中。这并不能解决问题。我不觉得没有调用处理程序有什么问题-调用太频繁了。