函数导致多次刷新组件

    <template v-for="(item, index) in checkList" :key="index">

            <a-tab-pane :tab="item.tabName">

              <Suspense>

                <component

                  :is="

                    DefineAsyncComponent(

                      () =>

                        import(

                          systemList.indexOf(item.componentName) !== -1

                            ? `./detail/${item.componentName}.vue`

                            : `../../developComponents/${item.componentName}/index.vue`

                        ),

                      {

                        loading: true,

                      },

                    )

                  "

                  :rev-data="show"

                  :key="item.id"

                  v-if="show && dataId && objectType"

                  :data="item"

                  @success="success"

                  @refresh="refreshData"

                  @changeShowFilter="changeShowFilter"

                  @close="close"

                  :isFilterEmpty="isFilterEmpty"

                  :isExportPdf="isExportPdf"

                  class="check-component"

                  :class="[

                    `${checkList[activeKey]['componentName'] === 'BaseInfo' ? 'pdfDom' : ''}`,

                    `${isExportPdf ? 'pdf-Class' : ''}`,

                  ]"

                />

                <template #fallback>

                  <a-skeleton active />

                </template>

              </Suspense>

            </a-tab-pane>

          </template>

在 Vue 中,如果你直接在 :is 中调用 defineAsyncComponent,例如:

vue

复制

<component :is="defineAsyncComponent(() => import('./MyComponent.vue'))" />

这种情况下,组件不会被缓存,每次渲染时都会重新加载。这是因为每次渲染时,defineAsyncComponent 都会创建一个新的异步组件实例,而不是复用之前的实例。


1. 为什么不会缓存?

原因 1:每次渲染都会重新调用 defineAsyncComponent
  • 在 Vue 的模板中,:is 绑定的表达式会在每次渲染时重新计算。

  • 如果你直接调用 defineAsyncComponent,每次渲染时都会创建一个新的异步组件实例,而不是复用之前的实例。

原因 2:defineAsyncComponent 返回一个新的组件
  • defineAsyncComponent 是一个工厂函数,每次调用都会返回一个新的异步组件实例。

  • 即使加载的是同一个组件文件,Vue 也会将其视为不同的组件实例。

原因 3:没有显式的缓存机制
  • 直接调用 defineAsyncComponent 时,没有显式的缓存逻辑来存储已经加载的组件实例。

  • 因此,每次渲染时都会重新加载组件。


2. 示例分析

以下代码会导致每次渲染时重新加载组件:

vue

复制

<template>
  <component :is="getAsyncComponent('MyComponent')" />
</template>

<script>
import { defineAsyncComponent } from 'vue';

export default {
  methods: {
    getAsyncComponent(componentName) {
      return defineAsyncComponent(() =>
        import(`./components/${componentName}.vue`)
      );
    },
  },
};
</script>
问题:
  • 每次渲染时,getAsyncComponent 方法都会被调用。

  • 每次调用 getAsyncComponent 时,都会创建一个新的异步组件实例。

  • 即使 componentName 相同,Vue 也会重新加载组件。


3. 如何实现缓存?

为了实现缓存,需要显式地存储已经加载的组件实例,并在后续渲染时复用这些实例。可以通过以下方式实现:

方法 1:使用全局缓存对象

在组件外部定义一个缓存对象,存储已经加载的组件实例:

javascript

复制

const componentCache = {};

const getAsyncComponent = (componentName) => {
  if (componentCache[componentName]) {
    return componentCache[componentName];
  }

  return componentCache[componentName] = defineAsyncComponent(() =>
    import(`./components/${componentName}.vue`)
  );
};

在模板中使用缓存后的组件:

vue

复制

<template>
  <component :is="getAsyncComponent('MyComponent')" />
</template>

<script>
import { defineAsyncComponent } from 'vue';

const componentCache = {};

const getAsyncComponent = (componentName) => {
  if (componentCache[componentName]) {
    return componentCache[componentName];
  }

  return componentCache[componentName] = defineAsyncComponent(() =>
    import(`./components/${componentName}.vue`)
  );
};

export default {
  methods: {
    getAsyncComponent,
  },
};
</script>
方法 2:使用 keep-alive

<keep-alive> 是 Vue 提供的内置组件,可以缓存动态组件的实例,避免组件被销毁和重新创建:

vue

复制

<keep-alive>
  <component :is="getAsyncComponent('MyComponent')" />
</keep-alive>
方法 3:将异步组件提升到全局

将异步组件定义在组件外部,确保只加载一次:

javascript

复制

const MyComponent = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
);

export default {
  components: {
    MyComponent,
  },
};

在模板中直接使用组件名:

vue

复制

<component :is="MyComponent" />

4. 直接调用 defineAsyncComponent 的问题

如果你直接调用 defineAsyncComponent,例如:

vue

复制

<component :is="defineAsyncComponent(() => import('./MyComponent.vue'))" />

每次渲染时都会发生以下过程:

  1. 调用 defineAsyncComponent,创建一个新的异步组件实例。

  2. 触发动态导入 (import()),加载组件文件。

  3. 组件加载完成后,渲染到页面上。

由于每次渲染都会创建一个新的异步组件实例,因此无法复用之前的实例,导致组件重新加载。


5. 总结

  • 直接在 :is 中调用 defineAsyncComponent 不会缓存组件,因为每次渲染都会创建一个新的异步组件实例。

  • 要实现缓存,需要显式地存储已经加载的组件实例(例如使用全局缓存对象),或者使用 <keep-alive> 来缓存组件实例。

  • 通过缓存机制,可以避免重复加载组件,提升性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值