首页 > 解决方案 > 具有标准化数据的 Vuex getter 不是响应式的

问题描述

我已经在 Vuex 应用程序中对我的数据进行了规范化,但我无法找到有关如何查看数据以进行更改的答案。例如,这是我的设置的简化版本。

状态:

const state = {
    shapes: {
        collection: [1, 2, 3],

        data: {
            1: {
                type: 'circle',
                isActive: false,
            },
        },
    }
}

吸气剂:

const getters = {
    findShape: (state) => (id) => {
        return state.shapes.data[id];
    }

    allShapes: (state, getters) => {
        return state.shapes.collection.map(id => getters.findShape(id));
    }
}

在我的组件中,我在计算属性中调用 allShapes getter,并通过 v-for 将形状向下传递给子组件。

computed: {
    shapes() {
        return this.$store.getters.allShapes;
    }
}

添加和删​​除形状工作正常。问题是每当我更新数据对象中的属性时,更改都不会反映在我的组件中。这是我设置 isActive 属性的突变:

const mutations = {
    setActive(state, shape) {
        Vue.set(state.shapes.data[shape.id], 'isActive', shape.isActive);
    }
}

然后引用 isActive 属性的任何组件都不会更新。我明白为什么会发生这种情况,但除了返回嵌套数组结构之外,我还没有找到解决方案。当数据对象发生变化时,有没有办法在 allShapes getter 中触发更新?或者是否有不同的方法可以将数据拉入我的组件以使其具有反应性?

标签: vue.jsvuex

解决方案


首先,关于Vue.set.

调用Vue.set有两件事:

  1. 如果该属性不存在,它会将其添加为反应性属性。
  2. 属性值将被更新。

这里有一个边缘案例。如果属性已经存在但不是反应性的,那么 usingVue.set不会增加反应性。

默认情况下, 的属性state将是反应性的,并且这种反应性将递归地应用于其中的所有对象和数组state。但是,通常的警告适用于添加新属性。Vue 无法检测到添加新属性,因此它不会是响应式的。这是Vue.set添加新属性的用例。

您很可能是从服务器加载数据以data填充state. 这是您需要使事情反应的关键点。当您来更新isActive物业时,可能为时已晚。

您可能有一个看起来像这样的突变:

addShape (state, shape) {
  state.shapes.data[shape.id] = shape
}

这是反应性下降的点,因为您要向state.shapes.data. 结果将是shape对象不会被反应系统处理,因此它的任何属性都不会是反应性的。

如果该isActive属性不存在,那么您实际上可能会侥幸逃脱。在那种情况下,使用Vue.set你会发现属性丢失并添加它,包括反应性。它实际上会做得更多。由于对象还没有反应,它将遍历整个对象并使所有属性都具有反应性。在这种情况下,唯一没有反应的是state.shapes.data.

但是,在您的情况下,该属性isActive似乎从一开始就存在。结果是Vue.set更改时无济于事isActive。相反,您首先需要在将对象添加到缓存时使用它。例如:

addShape (state, shape) {
  Vue.set(state.shapes.data, shape.id, shape)
}

显然,我对您如何填充缓存做了一些假设,state.shapes.data但即使您的代码与我描述的不完全一样,它也可能足够相似,可以应用相同的修复程序。

只要属性isActive从一开始就存在于形状对象中,就不需要isActive使用Vue.set. 使用它向缓存添加形状就足够了。


推荐阅读