为什么vue在更新自身时需要强制更新具有静态插槽的子组件
当一个组件具有大量具有静态插槽的子组件时,它将触发过多的更新计算
// my-button.vue
<template>
<div>
<slot></slot>
</div>
</template>
// my-com.vue
<template>
<div>
<span>{{ foo }}</span>
<template v-for="(item, index) in arr">
<my-button>test</my-button>
</template>
</div>
</template>
<script>
export default {
data() {
return {
foo: 1,
arr: (new Array(10000)).fill(1)
}
}
}
</scirpt>
如果运行this.foo = 2
将导致更新队列包括10000个观察者。当我阅读源代码时,发现以下代码
function updateChildComponent (
...
// Any static slot children from the parent may have changed during parent's
// update. Dynamic scoped slots may also have changed. In such cases, a forced
// update is necessary to ensure correctness.
const needsForceUpdate = !!(
renderChildren || // has new static slots
vm.$options._renderChildren || // has old static slots
hasDynamicScopedSlot
)
...
// resolve slots + force update if has children
if (needsForceUpdate) {
vm.$slots = resolveSlots(renderChildren, parentVnode.context)
vm.$forceUpdate()
}
...
}
答案 0 :(得分:1)
我在GitHub上找到了此issue。
不幸的是,所有具有静态插槽内容的子组件仍然 需要强制更新。这意味着
<parent><child></child></parent>
无法从此更改中受益, 除非默认插槽通过以下方式显式强制进入作用域插槽 使用<parent v-slot:default><child></child></parent>
。 (我们不可以 直接将所有插槽强行插入作用域内的插槽,因为那样会破坏 期望插槽中存在的现有渲染功能代码 {{1}中的this.$slots instead
)
似乎固定在this.$scopedSlots
中。
在2.6中,我们引入了优化功能,可以进一步确保父级 范围依赖项突变仅影响父项,而不再 如果子组件仅使用作用域的插槽,则强制其更新。
要解决您的问题,只需将Vue版本更新为2.6
。由于这只是次要更新,因此不会崩溃。打电话给2.6
的原因呢?只有 Evan You 知道:)
答案 1 :(得分:0)
你好,我用这个解决了这个问题:
export function proxySlots(scopedSlots: any): any {
return Object.keys(scopedSlots).reduce<any>(
(acc, key) => {
const fn = scopedSlots[key];
fn.proxy = true;
return { ...acc, [key]: fn };
},
{ $stable: true },
);
}
const ctx = {
// ...
scopedSlots: proxySlots({ someSlot: () => <span>Hello</span>})
// or from provided slots : this.$scopedSlots or context.slots if using composition api
}
有点黑,但不再需要强制更新。