如何防止组件收集不必要的依赖关系?

问题描述

我有一个基于某种嵌套状态的组件。例如

<rect width="some.deep.state.width">

只要更改此路径中的任何对象(不是新设置),即使没有任何更改,组件也会重新渲染。

例如,以下导致重新渲染:

Vue.set(some.deep,'newProp',something)

可以想象,这是非常不希望的,尤其是在存储中使用嵌套状态并且某些数组值发生更改时。

在我的情况下,我在商店中保存了多个实体,并且每当添加该实体的新实例时,即使没有任何更改,该实体的所有组件也会重新呈现。

那么有什么方法可以防止收集这种(技术上的)副手(双关语意)? 我可以通过某种机制阻止Vue收集侦探吗?

PS:我知道,此机制在其他地方也很有用。就我而言,这是不希望的

显示该行为的Codesandbox(在控制台中):https://codesandbox.io/s/vuejs-playground-forked-sx534?file=/components/hello.js

内联示例-触发更新:

const app = new Vue({
  el: '#app',data: function () {
    return { some: { nested: { prop: 6 }}}
  },created: function () {
    console.log('component created')
    
    setTimeout(function () {
    
      Vue.set(this.some,'otherProp',10)
    
    }.bind(this),2000)
  },updated: function () {
    console.log('component updated')
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
 Prop: {{ some.nested.prop }}
</div>

解决方法

我认为这个问题并不能阻止组件收集不必要的依赖关系。当您在模板中使用some.deep时,Vue renderWatcher已经收集了<rect width="some.deep.state.width">个依赖项。然后执行Vue.set(this.some.deep,'newProp',something)将通知所有收集的some.deep观察者,其中包括renderWatcher,它将触发重新呈现。

我有一个黑客解决方案,如果您确保不进行渲染,则它们将停止运行renderWatcher。

const app = new Vue({
  el: '#app',data: function () {
    return { some: { deep: { prop: 6 }}}
  },created: function () {
    console.log('component created')
    
    setTimeout(function () {
      console.log('trigger rerender?')
      Vue.set(this.some,'otherProp',10)
      this.preventRerender()
    }.bind(this),2000)
  },render(h) {
    console.log('render')
    return h('div',this.some.deep.prop)
  },methods: {
    // keep calling at the code end
    preventRerender() {
      this._watcher.active = false
      this.$nextTick(() => {
        this._watcher.active = true
      })
    }
  }
})

您必须注意,仍会触发更新的挂钩。

,

我这样做的最终方法是观察深层嵌套的属性。观察者似乎未注册我在问题中解释的更改。因此,我为每个属性添加了一个监视程序,该监视程序在组件上设置了一个属性,然后可以在模板中使用该属性。

这解决了不必要的重新渲染的问题,但是,事实证明,值同时更改的多个观察者每个都会触发重新渲染。 这很奇怪,因为所有观察者都在一个dom周期内执行,因此只能触发一次重新提交。如果有人知道原因,请随时进行详细说明!

const app = new Vue({
  el: '#app',data: function () {
    return {
      some: { nested: { prop: 6 }},theProp: null
    }
  },created: function () {
    console.log('component created')
    
    this.$watch(() => this.some.nested.prop,(newValue) => this.theProp = newValue,{immediate: true})
    
    setTimeout(() => {
    
      // Does not triggers update
      Vue.set(this.some,10)
    
    },2000)
    
    setTimeout(() => {
    
      // Triggers update
      this.some.nested.prop = 10
    
    },4000)
  },updated: function () {
    console.log('component updated')
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
 Prop: {{ theProp }}
</div>

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...