具有规范化数据的 Vuex getter 不是响应式的

Lia*_*rth 6 vue.js vuex

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

状态:

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

        data: {
            1: {
                type: 'circle',
                isActive: false,
            },
        },
    }
}
Run Code Online (Sandbox Code Playgroud)

吸气剂:

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

    allShapes: (state, getters) => {
        return state.shapes.collection.map(id => getters.findShape(id));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

computed: {
    shapes() {
        return this.$store.getters.allShapes;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

ski*_*tle 5

首先,介绍一下Vue.set.

调用Vue.set有两件事:

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

这里有一个边缘情况。如果该属性已经存在但不是反应性的,则使用Vue.set不会增加反应性。

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

最有可能你从服务器加载数据来填充data你的内对象state。当您需要使事情具有反应性时,这是关键点。当您来更新isActive属性时,可能为时已晚。

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

addShape (state, shape) {
  state.shapes.data[shape.id] = shape
}
Run Code Online (Sandbox Code Playgroud)

这是反应性下降的地方,因为您正在向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)
}
Run Code Online (Sandbox Code Playgroud)

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

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