我有一个基于某种嵌套状态的组件。例如
<rect width="some.deep.state.width">
每当此路径中的任何对象发生更改(不是新设置的(时,即使没有任何更改,组件也会重新渲染。
例如,以下情况会导致重新应答:
Vue.set(some.deep, 'newProp', something)
可以想象,这是非常不希望的,尤其是当在存储中使用嵌套状态并且某些数组值发生更改时。
在我的情况下,我将多个实体保存在我的存储中,每当添加该实体的新实例时,基于该实体的所有组件都会重新提交,即使没有任何更改。
那么,有没有办法防止收集这种(技术性的(deps(双关语(?我可以通过某种机制阻止Vue收集deps吗?
附言:我知道,这种机制在其他地方也很有用。在我的情况下,这不是想要的
显示该行为的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>
我认为这个问题并不能阻止组件收集不必要的依赖项。当您在模板中使用<rect width="some.deep.state.width">
时,Vue renderWatcher已经收集了some.deep
依赖项。然后执行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, 'otherProp', 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>