You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue中使用KeepAlive时仅在组件首次挂载时获取数据

实现KeepAlive缓存组件仅首次挂载请求数据的方案

你的需求是让被KeepAlive缓存的子组件,仅在首次挂载或请求地址变化时获取数据,从缓存激活时不再重复请求。可以通过以下两种方案解决:

方案一:通过状态标记控制请求时机

核心思路是用一个状态变量标记数据是否已加载,仅在首次挂载或requestUrl变化时触发请求,避免组件从缓存激活时重复执行请求逻辑。

修改子组件代码如下:

<template>
  <NavigationSubItem v-for="item in items" :key="item.id" />
  <div v-if="error">
    <button @click.prevent="refresh()">refresh</button>
  </div>
  <Loading v-if="pending" />
</template>

<script setup>
import { hash, ref, watch, onMounted } from 'vue';
import { useLazyFetch } from '#imports';

const props = defineProps({
  requestUrl: {
    type: String,
    required: true,
  },
});

// 标记数据是否已加载
const isLoaded = ref(false);
const items = ref([]);
const pending = ref(false);
const error = ref(null);
let refreshFn = () => {};

// 封装数据请求逻辑
const fetchData = async () => {
  pending.value = true;
  error.value = null;
  try {
    const { data, refresh } = await useLazyFetch(() => props.requestUrl, {
      key: hash(props.requestUrl),
      server: false,
      // 如果不需要no-cors模式可以移除,该模式下无法读取响应内容
      mode: 'no-cors',
    });
    items.value = data.value;
    refreshFn = refresh;
    isLoaded.value = true;
  } catch (err) {
    error.value = err;
  } finally {
    pending.value = false;
  }
};

// 首次挂载时触发请求
onMounted(() => {
  if (!isLoaded.value) {
    fetchData();
  }
});

// 监听requestUrl变化,重新请求数据
watch(() => props.requestUrl, () => {
  isLoaded.value = false;
  fetchData();
}, { immediate: false });

// 手动刷新方法
const refresh = () => {
  isLoaded.value = false;
  fetchData();
};
</script>

方案二:本地存储缓存请求结果(适配no-cors模式)

如果必须使用mode: 'no-cors',浏览器无法读取响应内容,此时useLazyFetch的缓存机制会失效,需要手动用本地存储缓存请求状态(注意:no-cors模式下无法获取响应数据,此方案适用于你实际能获取数据的场景,或可移除no-cors模式):

<template>
  <NavigationSubItem v-for="item in items" :key="item.id" />
  <div v-if="error">
    <button @click.prevent="refresh()">refresh</button>
  </div>
  <Loading v-if="pending" />
</template>

<script setup>
import { hash, ref, watch, onMounted } from 'vue';
import { useLazyFetch } from '#imports';

const props = defineProps({
  requestUrl: {
    type: String,
    required: true,
  },
});

const isLoaded = ref(false);
const items = ref([]);
const pending = ref(false);
const error = ref(null);

// 封装带本地缓存的请求逻辑
const fetchData = async () => {
  const cacheKey = `nav_sub_data_${hash(props.requestUrl)}`;
  const cachedData = localStorage.getItem(cacheKey);
  
  // 读取本地缓存(示例设置1小时有效期)
  if (cachedData) {
    const { data, timestamp } = JSON.parse(cachedData);
    if (Date.now() - timestamp < 3600 * 1000) {
      items.value = data;
      isLoaded.value = true;
      return;
    }
  }

  pending.value = true;
  error.value = null;
  try {
    const { data } = await useLazyFetch(() => props.requestUrl, {
      key: hash(props.requestUrl),
      server: false,
      mode: 'no-cors',
    });
    // 缓存数据到本地
    localStorage.setItem(cacheKey, JSON.stringify({
      data: data.value,
      timestamp: Date.now()
    }));
    items.value = data.value;
    isLoaded.value = true;
  } catch (err) {
    error.value = err;
  } finally {
    pending.value = false;
  }
};

onMounted(() => {
  if (!isLoaded.value) {
    fetchData();
  }
});

watch(() => props.requestUrl, () => {
  isLoaded.value = false;
  fetchData();
}, { immediate: false });

const refresh = () => {
  isLoaded.value = false;
  fetchData();
};
</script>

关键说明

  • KeepAlive包裹的组件,onMounted仅执行一次,onActivated会在每次组件从缓存激活时执行,因此用isLoaded状态可以避免重复请求。
  • 监听requestUrl变化,确保当请求地址改变时能重新获取最新数据。
  • 如果不需要no-cors模式,建议移除该配置,否则无法读取响应内容,缓存逻辑也会受限。

内容的提问来源于stack exchange,提问作者Neatpixels

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 15:15:02