Vue Reactivity:为啥替换对象的属性(数组)不会触发更新

Posted

技术标签:

【中文标题】Vue Reactivity:为啥替换对象的属性(数组)不会触发更新【英文标题】:Vue Reactivity: Why replacing an object's property (array) does not trigger updateVue Reactivity:为什么替换对象的属性(数组)不会触发更新 【发布时间】:2020-09-17 08:06:47 【问题描述】:

我有一个 Vue 应用程序,我正在尝试在 Mapbox API 上制作一个瘦包装器。我有一个包含一些简单 geojson 数据的组件,当更新该数据时,我想在地图上调用渲染函数以使用该新数据更新地图。一个 Vue 观察者应该能够做到这一点。但是,当数据发生变化时,我的观察者不会被调用,我怀疑这是 vue 反应性无法捕捉到的情况之一。我知道我可以使用this.$set 轻松解决这个问题,但我很好奇为什么这不是一个被动更新,即使根据我对规则的理解它应该是。这是相关的数据模型:

data() 
  return
    activeDestinationData: 
      type: "FeatureCollection",
      features: []
    
  

然后我有一个观察者:

watch: 
  activeDestinationData(newValue) 
    console.log("Active destination updated");
    if (this.map && this.map.getSource("activeDestinations")) 
      this.map.getSource("activeDestinations").setData(newValue);
    
  ,

最后,在我的应用程序逻辑中,我通过将数组完全重新分配给具有一项的新数组来更新 activeDestination 上的功能:

// Feature is a previously declared single feature
this.activeDestinationData.features = [feature];

由于某种原因,观察者永远不会被调用。我读到了一些反应性“陷阱”here,但这两种情况都不适用于这里:

Vue 无法检测到数组的以下更改:

当您直接使用索引设置项目时,例如vm.items[indexOfItem] = newValue

当您修改数组的长度时,例如vm.items.length = newLength

我在这里遗漏了什么导致反应不发生?对于预期行为this.set() 是我唯一的选择还是有更优雅的解决方案?

【问题讨论】:

【参考方案1】:

如果你需要观察一个深层结构,你必须写一些参数

watch: 
  activeDestinationData: 
      deep: true,
      handler()  /* code... */ 

您可以在那里阅读更多信息 -> https://vuejs.org/v2/api/#watch 希望对你有帮助:)

【讨论】:

【参考方案2】:

因为默认 vue 会进行浅比较,并且由于您正在改变数组而不是替换,因此它的参考值是相同的。您需要在更新其内容时传递一个新的数组引用,或者传递选项deep: true 以查看嵌套值的变化:

watch: 
  activeDestinationData: 
    handler(newValue) 
      console.log("Active destination updated");
      if (this.map && this.map.getSource("activeDestinations")) 
        this.map.getSource("activeDestinations").setData(newValue);
      
    ,
    deep: true
  

【讨论】:

以上是关于Vue Reactivity:为啥替换对象的属性(数组)不会触发更新的主要内容,如果未能解决你的问题,请参考以下文章

Vue3 响应式解析Reactivity(Reflect and Proxy)

Vue 3.0 的生命周期

深入理解Vue数据响应式

vue响应式原理整理

记录学习vue-next源码 - reactivity

Vue3.0源码系列响应式原理 - Reactivity