Pinia 优化重复请求-小兔鲜项目普通导航与吸顶导航请求两次数据

要优化的原因

如上图,普通导航与吸顶导航中的列表是完全一致的,但是要发送两次网络请求,存在浪费。

解决: 通过 Pinia 集中状态管理数据,再把数据分发给组件使用。

复习一下两个组件请求的大致步骤

  1. 在utils/http.js 文件里进行 axios 实例 httpInstance 的创建,进行一些默认配置,如 baseURL 基地址、timeout 请求超出时间。
  2. 在apis/Layout.js 引入实例httpInstance,封装获取分类的函数 getCategoryAPI(),在函数内部使用实例发送请求,并导出函数将其暴露出去。
  3. 在目标组件中,导入封装好的函数,再单独编写一个获取数据的业务函数 getCategory()并进行 async 修饰,在业务函数内部使用变量 res 来接收通过封装好的函数请求到的数据,再用响应式变量接收进行赋值,然后在onMounted钩子函数中调用getCategory()函数,最后在模版中 v-for 渲染categoryList。

核心优化原理

1. 状态提升

  • 将共享数据从组件内部提升到全局Store中
  • 避免多个组件各自维护相同数据

2. 请求去重

  • 通过统一的action触发请求
  • 确保相同数据只请求一次

3. 数据共享

  • 多个组件共享同一份数据源
  • 数据更新时所有组件自动同步

代码实现

步骤一: 新增 stores/category.js 分类列表

javascript 复制代码
<!-- 导入 -->
import { defineStore } from 'pinia'
import { ref } from 'vue' 
import { getCategoryAPI } from '@/apis/layout' 

// 使用defineStore方法
// 参数一为标识,是一个字符串,参数二为回调函数
// 在defineStore方法里 属性就是state 函数就是action
export const useCategoryStore = defineStore('category', () => {
// 导航列表的数据管理  -和之前在组件里的写法一样
// state 导航列表数据 action获取导航数据的方法
const categoryList = ref([])
const getCategory = async () => {
    //逻辑
    const res = await getCategoryAPI()
    categoryList.value = res.result
}

// 要想在组件里面用 需要以对象的方式把数据和函数return出去
return { categoryList, getCategory }
})

为什么不需要在 store 中使用 onMounted?(Store与组件生命周期的关注点分离)

  • Store的职责:
    • 管理应用状态(state)
    • 提供修改状态的方法 (actions)
    • 保持数据的一致性和可预测性
    • 不应该包含组件特定的逻辑
  • 组件的职责:
    • 管理UI渲染
    • 处理用户交互
    • 控制组件生命周期
    • 调用Store的actions来获取或修改数据

步骤二: 在两个导航的父组件 Layout/index.vue 中 触发获取导航列表的 action

javascript 复制代码
// 触发获取导航列表的action -导入 执行 调用内部函数

import { onMounted } from 'vue'

// 导入 use 开头的方法
import { useCategoryStore } from '@/stores/category' 

// 执行 useCategoryStore 方法 得到实例对象 categoryStore
const categoryStore = useCategoryStore()

// 在 onMounted 钩子中 通过这个实例对象调取内部的 action 函数 getCategory()
onMounted(async () => {
await categoryStore.getCategory()
console.log(
        categoryStore.categoryList,
        'Layout组件调用getCategory方法,用async修饰可以确保在数据返回后再进行操作,这样可以输出categoryStore.categoryList,否则会输出array[0]'
        )
})

注意的点:用 async 修饰钩子函数 onMounted 可以确保在数据返回后再进行操作

步骤三: 在两个子组件即普通导航组件和吸顶导航组件里面导入 use 开头的方法,执行得到实例对象,通过实例对象拿到里面的 CategoryList(步骤二使得里面已经获取到数据了),最后在模版中渲染数据即可

xml 复制代码
<script setup>
import { useCategoryStore } from '@/stores/category'
const categoryStore = useCategoryStore()
</script>

<template>
<li v-for="item in categoryStore.categoryList" :key="item.id">
    {{ item.name }}
</li>
</template>

最佳实践建议

1. Store设计原则

  • 按业务领域划分Store
  • 保持Store职责单一
  • 合理组织state和action

2. 数据获取时机

  • 在合适的组件层级触发数据获取
  • 避免在多个组件中重复触发相同请求
  • 考虑数据的缓存和更新策略

结语

  • 仅在父组件 Layout/index.vue 中请求了一次数据
  • head普通导航组件和fixed吸顶导航组件直接使用Store中的数据
  • 实现了请求去重和数据共享的目标
相关推荐
计算机学姐5 分钟前
基于SpringBoot的汉服租赁系统【颜色尺码套装+个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·mysql·信息可视化·推荐算法
+VX:Fegn08956 分钟前
计算机毕业设计|基于springboot + vue建筑材料管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
雪碧聊技术13 分钟前
ElementPlus徽章组件:展示日期面板每天未完成的待办数量
vue.js·日期选择器·elementplus·el-badge徽章组件
沐墨染2 小时前
敏感词智能检索前端组件设计:树形组织过滤与多维数据分析
前端·javascript·vue.js·ui·数据挖掘·数据分析
xkxnq2 小时前
第二阶段:Vue 组件化开发(第 18天)
前端·javascript·vue.js
WebGISer_白茶乌龙桃2 小时前
Cesium实现“悬浮岛”式,三维立体的行政区划
javascript·vue.js·3d·web3·html5·webgl
计算机学姐3 小时前
基于SpringBoot的汽车租赁系统【个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·spring·汽车·推荐算法
不一样的少年_3 小时前
产品催: 1 天优化 Vue 官网 SEO?我用这个插件半天搞定(不重构 Nuxt)
前端·javascript·vue.js
BingoGo3 小时前
免费可商用商业级管理后台 CatchAdmin V5 正式发布 插件化与开发效率的全面提升
vue.js·后端·php
一 乐11 小时前
婚纱摄影网站|基于ssm + vue婚纱摄影网站系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端