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中的数据
  • 实现了请求去重和数据共享的目标
相关推荐
qq. 28040339843 小时前
vue介绍
前端·javascript·vue.js
全栈前端老曹5 小时前
【前端组件封装教程】第3节:Vue 3 Composition API 封装基础
前端·javascript·vue.js·vue3·组合式api·组件封装
BruceeLeee5 小时前
关于vue3中使用el-upload组件上传图片后删除和预览按钮不显示的问题
vue.js
源码宝5 小时前
企业项目级医院随访系统源码,患者随访管理系统,技术框架:Java+Spring boot,Vue,Ant-Design+MySQL5
java·vue.js·spring·程序·医院管理系统·随访·随访系统源码
香香爱编程6 小时前
electron对于图片/视频无法加载的问题
前端·javascript·vue.js·chrome·vscode·electron·npm
蒲公英源码8 小时前
基于PHP+Vue+小程序快递比价寄件系统
vue.js·小程序·php
许___9 小时前
el-table多选模式下跨分页保留当前页选项
javascript·vue.js
程序定小飞10 小时前
基于springboot的学院班级回忆录的设计与实现
java·vue.js·spring boot·后端·spring
攀小黑11 小时前
基于若依-内容管理动态修改,通过路由字典配置动态管理
java·vue.js·spring boot·前端框架·ruoyi
Rysxt_11 小时前
Vuex 教程 从入门到实践
前端·javascript·vue.js