【问题标题】:Vue.js list rendering diff: "same object" vs "has same values"Vue.js 列表渲染差异:“相同的对象”与“具有相同的值”
【发布时间】:2021-02-14 13:00:10
【问题描述】:

我刚刚在 Vue.js (2.6.12) 组件中遇到了反应性问题。在其道具更新后,它没有重新计算和重新渲染。问题是该组件在v-forkey 的列表中使用。 key 没有改变,但对象的数据在改变,即它是同一个对象,但它的数据不同。

key 被用作区分v-for 中的列表的优化,因此它可以重复使用和重新排序相同的组件而无需重新创建它们。我原来的key 是对象的id,解决方案是从id 和所有对象的变化数据创建key。这会导致其他问题,例如丢失组件的内部数据状态,无需将其存储在 Vuex 存储中。

我的问题是,在 Vue.js(可能在 v3 中?)中是否有办法在 v-for 中判断对象是否相同(通过 key 使用对象的 id)以及对象是否具有相同的数据?哪个会更新 prop 并重新计算和重新渲染组件而不会丢失其内部数据?

有趣的是组件的 props 正在更新,它只是没有重新计算和重新渲染。通过浏览器中的 Vue Devtools 验证。

编辑:

Here is an example 反应性不起作用。它使用 Vuex 存储,v-for 的数组是一个计算属性,它连接了存储中的两个属性。

我刚刚发现问题在于通过67: o.number = extras[o.id] 线上的map 加入值。将其替换为 Vue.set(o, 'number', extras[o.id]) 后,它正在工作!

【问题讨论】:

  • 最好给出一个简化的代码示例来重现问题,让其他人确切地看到你是如何使用这些道具的等等。因为当一切都正确完成时,就不存在上面描述的这种反应性问题。一个小例子:jsfiddle.net/sh0ber/04s1jt8g
  • @Dan 我很惊讶它正在工作。我什至用默认值的Object 类型的道具修改了那个小提琴,并绑定了整个对象,而不仅仅是它的值,即<comp v-for="obj in objs" :key="obj.id" :value="obj"></comp>,它仍在工作。也许这与 Vuex 商店有关?我的问题是 Vue Devtools 显示道具已更改,但未重新计算计算属性并且未重新绘制组件。我会尝试用 Vuex 做一个最小的演示。
  • 这种反应性是 Vue 的主要特性,因此它可以更好地工作。如果我不得不猜测,您遇到的对象是change detection caveat,需要使用Vue.set。例如,当动态创建 Vuex 状态项时。请注意,在我的示例中,所有数据属性都预先存在,因此不存在该问题
  • @Dan 你是对的Vue.set!而且我认为它咬了我很多次,以至于我知道自己在做什么:D 这里有点复杂,因为v-for 的数组是一个计算属性,它连接了来自 Vuex 商店甚至在@987654342 中的两个属性@我不得不使用Vue.set。请检查我添加到问题中的示例。您能否评论一下为什么在这种情况下还需要Vue.set?谢谢。
  • 这是因为您的计算在每个 Vuex obj 上创建了一个新属性 (number),在您设置 objs 时未在 Vuex 中定义。如果您已将objs 初始化为也具有number 属性,则不需要Vue.set。另一种证明它的方法是设置o.text 而不是o.number,你会看到它在没有Vue.set 的情况下是被动的。顺便说一句,在 Vuex getter 中而不是在计算中进行此计算更有意义; getter 是为 Vuex 计算的。将逻辑与组件解耦很好,假设您需要多个组件中的结果

标签: vue.js key diff v-for


【解决方案1】:

此问题不存在描述。这是对象反应性正常工作的一个小例子:https://jsfiddle.net/sh0ber/04s1jt8g

不过,我猜你遇到的是change detection caveat,需要使用Vue.set

现在代码示例清楚了原因:您的计算在每个 Vuex obj 上创建了一个新属性 (number),在您设置 objs 时未在 Vuex 中定义。如果您已将objs 初始化为也具有number 属性,则不需要Vue.set。另一种证明它的方法是设置o.text 而不是o.number,你会看到它在没有Vue.set 的情况下是被动的

(顺便说一句,在 Vuex 的 getter 中而不是在计算中进行计算更有意义;getter 是为 Vuex 计算的。将逻辑与组件解耦很好,并想象您需要多个组件中的结果)

【讨论】:

  • Vue.set 的最后一个问题是它正在修改 Vuex 存储突变之外的对象。这可以通过在map 中通过Object.assign(...) 制作对象的副本来解决。
  • True,这将绕过整个反应性问题。您不需要 Vue.set 并且您的数据可能会使 number 未初始化
猜你喜欢
  • 2019-06-28
  • 2012-03-13
  • 1970-01-01
  • 2015-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-20
  • 1970-01-01
相关资源
最近更新 更多