【问题标题】:Vuex getters with normalized data is not reactive具有规范化数据的 Vuex getter 不是响应式的
【发布时间】:2020-03-22 10:59:54
【问题描述】:

我已经在 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.js vuex


    【解决方案1】:

    首先,关于Vue.set 的一些背景知识。

    调用Vue.set 会做两件事:

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

    这里有一个极端情况。如果属性已经存在但不是反应性的,那么使用Vue.set 不会增加反应性。

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

    您很可能从服务器加载数据以填充state 中的data 对象。这是您需要使事情反应的关键点。当您来更新 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 从一开始就存在于形状对象中,就不需要使用Vue.set 设置isActive。使用它向缓存中添加形状就足够了。

    【讨论】:

    • 这是 Vue.set 的一个很好的细分。这些形状实际上是对在页面加载后创建的谷歌地图对象的引用,但是创建形状的突变中的 Vue.set(state.shapes.data, shape.id, shape) 正是问题所在。你是一个学者,一个绅士。
    猜你喜欢
    • 2020-05-26
    • 2012-12-11
    • 2017-05-28
    • 2012-03-22
    • 1970-01-01
    • 2021-09-30
    • 2021-02-11
    • 2018-07-08
    • 1970-01-01
    相关资源
    最近更新 更多