当前位置: 首页 > 知识库问答 >
问题:

vue.js - vue的slot中的子组件每次都会被update,频繁update导致性能低下,如何避免?

姬高澹
2024-12-26

如这个样例(请点击后查看Console变化):
https://codepen.io/hzsrc/pen/gbYxOry

只要组件中任何状态发生变化,vue的slot中的子组件每次都会被update,频繁update导致性能低下。

一些大组件(比如多行多列的表格),里面有上千个单元格子组件,每次只要修改表格的任何一个属性,都会导致整个表几千个子组件全部update,造成严重的性能问题。

这属于bug吗,有没有办法避免不必要的update吗?

共有2个答案

孙斌
2024-12-26

vue2里,父级render,插槽内容也会强制render
和我以前的问题是一样的https://segmentfault.com/q/1010000039280732

要解决的话就是不用插槽,改为传入render函数

谭嘉容
2024-12-26

如果是vue3

可以使用 v-memo 指令来缓存组件的渲染结果,只有当 row.checked 发生变化时,相关的 cell 组件才会重新渲染

<template>
  <div>
    <section>
      <div v-for="row in rows" :key="row.pkey" v-memo="[row.checked]">
        <button @click="row.checked=!row.checked">Change checked, one slot updated:</button>
        <cell>
          <template #default><span>{{row.checked}}</span></template>
        </cell>
      </div>
    </section>
    <hr>
    <section>
      <button @click="num++">Change num, 10 slot updated:</button>
      {{num}}  <span style="color:red">Why this causes 10 slots updated? The slots even not depend on this `num` value!</span>
    </section>
  </div>
</template>

<script>
const cell = {
  template: '<span><slot></slot></span>',
  updated() {
    console.log('cell updated')
  }
}

export default {
  data() {
    return {
      rows: newArr(),
      num: 0,
    }

    function newArr() {
      var rows = []
      for (var i = 0; i < 10; i++) {
        rows.push({ checked: 0, pkey: i })
      }
      return rows
    }
  },
  components: { cell },
}
</script>

如果是vue2

  1. 组件拆分:

    • 将 num 相关的内容抽离成独立的 NumSection 组件
    • 这样当 num 变化时,只会触发 NumSection 组件的更新,而不会影响到其他组件
  2. 优化 cell 组件:

    • 添加 key 属性来帮助 Vue 更好地追踪组件状态
    • 可以在子组件中实现 shouldComponentUpdate 来控制更新
    • 确保只有当 checked 值真正改变时才更新组件
  3. 响应式处理:

    • 使用 this.$set 来确定数组元素属性的修改能够触发响应式更新
    • 这是 Vue 2 中的一个特殊要求,在 Vue 3 中则不需要
<template>
  <div>
    <section>
      <div v-for="row in rows" :key="row.pkey">
        <button @click="toggleChecked(row)">Change checked, one slot updated:</button>
        <cell 
          :checked="row.checked"
          :key="`cell-${row.pkey}`"
        >
          <template #default><span>{{row.checked}}</span></template>
        </cell>
      </div>
    </section>
    <hr>
    <section>
      <!-- 将num相关的内容抽离成单独的子组件 -->
      <num-section :num="num" @increment="incrementNum"></num-section>
    </section>
  </div>
</template>

<script>
// 子组件:cell
const cell = {
  props: ['checked'],
  template: '<span><slot></slot></span>',
  name: 'Cell',
  // 添加更新控制
  shouldComponentUpdate(nextProps) {
    return nextProps.checked !== this.checked;
  },
  updated() {
    console.log('cell updated')
  }
}

// 将num相关的内容抽离成独立组件
const NumSection = {
  name: 'NumSection',
  props: ['num'],
  template: `
    <div>
      <button @click="$emit('increment')">Change num:</button>
      {{num}}
    </div>
  `
}

export default {
  name: 'RowList',
  data() {
    return {
      rows: this.createRows(),
      num: 0,
    }
  },
  methods: {
    createRows() {
      return Array.from({ length: 10 }, (_, i) => ({
        checked: false,
        pkey: i
      }))
    },
    toggleChecked(row) {
      // Vue 2中对数组元素属性的修改需要使用 $set 才能保证响应式
      this.$set(row, 'checked', !row.checked)
    },
    incrementNum() {
      this.num++
    }
  },
  components: { 
    cell,
    NumSection
  }
}
</script>
 类似资料:
  • 问题内容: 我正在尝试在PHP中创建SQL查询以更新表。每个受影响的行都有可能有不同的子句吗? 例如: 等等? 任何帮助表示赞赏。谢谢 问题答案: 任何SQL语句都不能有多个WHERE子句,但是可以使用CASE语句来完成您要尝试执行的操作。您拥有的另一个选择是执行多个UPDATE语句。 这是使用CASE语句的示例: 这是使用多个UPDATE语句的示例:

  • 本文向大家介绍Vue.js中组件中的slot实例详解,包括了Vue.js中组件中的slot实例详解的使用技巧和注意事项,需要的朋友参考一下 Vue组件中的slot slot 可以实现在已经定义的组件中添加内容,组件会接收内容并输出,假如有一个组件person,它的里面包含的是个人信息,如下面这样 在应用的时候,当然希望这里面可以是灵活变化的,所以这就需要用到slot了 首先要做的事情就是创建这样一

  • vue使用<component>动态组件,切换两个包含<el-table>的页面。反复切换后会导致列的类名不断变化。 如下:选择的标签是同一页面的el-table的同一位置。 初次加载时: 反复切换后: 不清楚是什么原因导致。

  • 目前遇到的一个场景,需要在事务的最后对一些数据的状态进行变更。 这些需要update的数据可能是1000条,也可能是1万条。 因为这张表的读写频率很高,如果在事务里执行一个update table set status = 1 where x(数据量1000-10000),那么会有几率出现死锁吗? 所以这就引出了一个问题,update的底层原理是啥?执行一句这样的update性能如何?

  • 问题内容: 我创建了一个电子邮件队列数据库表。我将把我的PHP应用程序需要发送的所有电子邮件插入此表。 然后,另一个PHP脚本将查找所有未发送的电子邮件并将其发送。 我使用cronjobs运行此脚本。不幸的是,cronjobs每分钟最多只能运行一次。因此,在最坏的情况下,用户必须等待一分钟,直到真正发送他的电子邮件为止。 我目前的解决方法是,使用附加的sleep参数调用脚本并复制cronjobs。

  • 如何在Children内部拿到父级的ref? 父级是不同的组件

  • 来源完全错误... 希望有人能帮助马克

  • 问题内容: 如果我的ID,然后用这些ID,那么查询是比我快会使用的条件。 为了显示: 在相同条件下,上述速度比大约快100倍: 为什么? 注意:该列 已建立 索引。 问题答案: 第二条语句很可能会锁定更多行,而第一条语句使用唯一键并仅锁定要更新的行。