一不小心就踩了 keep-alive 的坑

发布时间:2024-01-10 11:24 分类:Vue

前言

keep-alive 是 Vue 提供的一个内置组件,主要用来缓存动态组件或路由视图。当组件被包裹在 keep-alive 中时,切换页面后该组件不会被销毁,而是被缓存起来,下次切换回来时,组件会保持上一次的状态。

典型用法:

<template>
  <!-- 通过 v-slot 传递路由组件 -->
  <router-view v-slot="{ Component }">
    <!-- 通过 keep-alive 保持组件活性 -->
    <keep-alive>
      <!-- 通过 Component 自定义渲染路由组件 -->
      <Component :is="Component"></Component>
    </keep-alive>
  </router-view>
</template>

Vue 中,keep-alive 是一个非常实用的组件,通过缓存路由组件,可以优化性能和提升用户体验。而它也是一把双刃剑,随时等着你入坑!本文则围绕几个常见的使用场景,教大家如何避免 keep-alive 陷阱。

keep-alive 常见的坑

1. 生命周期钩子与预期不符

// 没有被 keep-alive 包裹的组件
onMounted(() => {
  getList(); // 组件每次打开时都会调用此方法
})

// 被 keep-alive 包裹的组件
onMounted(() => {
  getList(); // 组件只有第一次打开时会调用此方法
})

在 Vue 组件的生命周期中,组件挂载就会触发 onMounted 生命周期钩子,组件取消挂载就会触发 onUnMounted 生命周期钩子。

Vue生命周期流程图

但组件在 <keep-alive> 包裹下,创建后的组件实例会被缓存,即便是切换至其他组件,也不会导致该组件被销毁。所以onMounted 只会触发一次,onUnMounted 不会触发。取而代之的是 onActivatedonDeactivated 钩子,分别在组件被激活停用时触发。

需要注意的是,onActivatedonDeactivated 只在 <keep-alive> 下生效!

2. 无法重置数据状态

如果在 keep-alive 包裹下的组件中填写了一个表单,那么下次打开这个组件时,表单的内容可能没有被重置。同样的,如果是获取了一个数据列表,那么这个数据列表的值无论组件打开多少次都不会发生变化,因此无法获取最新的数据。

此时,需要我们人为的在 onActivated 生命周期钩子中触发重置表单或重新获取数据列表的逻辑。

3. 路由参数变化时无法监听

当使用动态路由时,路由参数变化但组件未更新。例如:/user/1 切换到 /user/2 后,仍然显示的是用户 1 的数据。因此,将读取路由参数的逻辑置于 onMounted 就失去了作用。

改为使用 watch 来监听路由的变化,非常有效!

const route = useRoute();

// 监听路由变化,动态加载数据
watch(
  () => route.params.id, // 监听 id 的变化
  (newId) => {
    getUserData(newId); // 加载新数据
  }
);

4. 缓存组件过多导致内存占用高

如果 keep-alive 缓存了过多的组件,可能会导致内存占用过高,页面卡顿,甚至浏览器崩溃。使用 includeexclude 属性限制缓存的组件:

<!-- 以英文逗号分隔的字符串 -->
<KeepAlive include="a,b">
  <component :is="view" />
</KeepAlive>

<!-- 正则表达式 (需使用 v-bind) -->
<KeepAlive :include="/a|b/">
  <component :is="view" />
</KeepAlive>

<!-- 数组 (需使用 v-bind),可以动态控制 -->
<KeepAlive :include="['a', 'b']">
  <component :is="view" />
</KeepAlive>

5. 与第三方库不兼容

某些第三方库(如动画库、滚动插件)依赖组件的初始化逻辑,在组件缓存后无法正常工作。keep-alive 下的 onMounted 会失效,因此,应该在 onActivate 钩子中重新初始化第三方库。

总结

keep-alive 是 Vue 提供的强大工具,用于优化组件性能和用户体验,但也隐藏着诸多陷阱。开发中需注意组件的生命周期变化,合理使用 onActivated 和 watch 解决数据状态重置和路由参数更新问题。同时,避免缓存过多组件以防内存占用过高,必要时使用 include 和 exclude 进行缓存控制。谨慎处理与第三方库的兼容性,确保组件在缓存和激活后的功能正常。合理规避这些问题,才能更好地发挥 keep-alive 的作用。

了解更多

Vue生命周期
keep-alive