当vue组件包含静态插槽时,为什么要强制更新组件

时间:2019-08-17 11:57:04

标签: vue.js

为什么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()
  }
...
}

2 个答案:

答案 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 
}

有点黑,但不再需要强制更新。