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

Vue + Pinia数据存储优化:分类页面数据混淆问题咨询

解决方案:Pinia中按查询维度缓存商品数据

问题根源在于现有代码把所有页面数据存入同一个数组,未区分查询条件,导致切换分类后仍能获取到其他场景下的页码数据。无需为每个查询条件单独创建state变量,通过按查询维度分组缓存的方式,既能实现本地数据复用,又能避免数据混淆。

1. 调整State结构

将原有的pages数组改为按查询标识分组的缓存对象,同时新增currentQueryKey记录当前页面使用的查询标识(可选,方便组件统一获取数据):

state: (): ProductState => ({
  product: {} as Product,
  // 缓存结构:{ 查询标识: 该标识下的页面数组 }
  cache: {} as Record<string, PageableType<Product>[]>,
  isRequestLoading: false,
  // 记录当前活跃的查询标识
  currentQueryKey: ""
}),

2. 定义唯一查询标识

为不同查询场景生成唯一key,确保缓存区分:

  • 首页普通商品:"default"
  • 指定分类商品:"category_${categoriesId}"
  • 促销商品:"promotion"
    复杂筛选场景可将参数序列化为字符串作为key(如"category_1_price_0-100")。

3. 修改Getters

新增根据查询标识和页码获取缓存数据的方法:

getters: {
  // 根据查询标识+页码获取缓存页面
  getCachedProducts(state) {
    return (queryKey: string, pageNumber: number) => {
      const pageList = state.cache[queryKey] || [];
      return pageList.find(page => page.number === pageNumber);
    };
  },
  // 获取当前查询标识下的所有页面
  currentPageList(state) {
    return state.cache[state.currentQueryKey] || [];
  }
},

4. 重构Actions加载逻辑

每个加载方法先检查缓存,存在则直接复用,不存在再请求后端并更新缓存:

actions: {
  async loadProduct(pageNumber: number, pageSize: number) {
    const queryKey = "default";
    // 命中缓存则直接返回
    const cachedPage = this.getCachedProducts(queryKey, pageNumber);
    if (cachedPage) {
      this.isRequestLoading = false;
      this.currentQueryKey = queryKey;
      return;
    }
    this.isRequestLoading = true;
    const res = await ProductActions.loadProduct(pageNumber, pageSize);
    this.updateCache(queryKey, res);
    this.currentQueryKey = queryKey;
    this.isRequestLoading = false;
  },

  async loadProductByCategories(pageNumber: number, pageSize: number, categoriesId: number) {
    const queryKey = `category_${categoriesId}`;
    const cachedPage = this.getCachedProducts(queryKey, pageNumber);
    if (cachedPage) {
      this.isRequestLoading = false;
      this.currentQueryKey = queryKey;
      return;
    }
    this.isRequestLoading = true;
    const res = await ProductActions.loadProductByCategories(pageNumber, pageSize, categoriesId);
    this.updateCache(queryKey, res);
    this.currentQueryKey = queryKey;
    this.isRequestLoading = false;
  },

  async loadProductInPromotion(pageNumber: number, pageSize: number) {
    const queryKey = "promotion";
    const cachedPage = this.getCachedProducts(queryKey, pageNumber);
    if (cachedPage) {
      this.isRequestLoading = false;
      this.currentQueryKey = queryKey;
      return;
    }
    this.isRequestLoading = true;
    const res = await ProductActions.loadProductInPromotion(pageNumber, pageSize);
    this.updateCache(queryKey, res);
    this.currentQueryKey = queryKey;
    this.isRequestLoading = false;
  },

  // 统一更新缓存方法
  updateCache(queryKey: string, payload: PageableType<Product>) {
    if (!this.cache[queryKey]) {
      this.cache[queryKey] = [];
    }
    // 避免重复添加相同页码,支持更新旧数据
    const existingIndex = this.cache[queryKey].findIndex(page => page.number === payload.number);
    if (existingIndex !== -1) {
      this.cache[queryKey][existingIndex] = payload;
    } else {
      this.cache[queryKey].push(payload);
    }
  }
}

5. 组件中使用示例

<template>
  <div v-if="!isRequestLoading">
    <ProductItem 
      v-for="product in currentPageList.find(p => p.number === currentPage)?.content || []" 
      :key="product.id" 
      :product="product"
    />
  </div>
</template>

<script setup>
import { storeToRefs } from 'pinia';
import { storeModule } from '@/stores/product';
import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';

const route = useRoute();
const productStore = storeModule();
const { isRequestLoading, currentPageList } = storeToRefs(productStore);
const currentPage = ref(0);

onMounted(() => {
  // 加载当前分类下的商品
  productStore.loadProductByCategories(currentPage.value, 10, route.params.categoryId);
});
</script>

额外优化建议

  • 给缓存添加过期时间:在state中记录缓存时间戳,加载时判断是否过期,避免长期保留旧数据。
  • 分维度管理加载状态:将isRequestLoading改为loadingStates: Record<string, boolean>,避免切换查询时加载状态混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:55:11