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中的数据
  • 实现了请求去重和数据共享的目标
相关推荐
计算机学姐25 分钟前
基于微信小程序的扶贫助农系统【2026最新】
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis
蓝莓味的口香糖27 分钟前
【企业微信】VUE项目在企微中自定义转发内容
前端·vue.js·企业微信
cg.family34 分钟前
Vue3 v-slot 详解与示例
前端·javascript·vue.js
我是日安1 小时前
从零到一打造 Vue3 响应式系统 Day 18 - Reactive:深入 Proxy 的设计思路
前端·vue.js
_AaronWong1 小时前
多页面应用登录状态共享:基于弹出窗口的通用解决方案
前端·javascript·vue.js
六月的可乐1 小时前
Vue接入AI聊天助手实战
前端·vue.js·人工智能
南风木兮丶2 小时前
Vue 项目安装 @antfu/eslint-config 保姆级教程
前端·javascript·vue.js
mldong2 小时前
保姆级教程!手把手教你搭建FastAPI + Vue3前后端分离项目
vue.js·python·全栈
java水泥工3 小时前
学科竞赛管理系统|基于SpringBoot和Vue的学科竞赛管理系统(源码+数据库+文档)
数据库·vue.js·spring boot
千里码aicood3 小时前
python+vue智慧物业管理系统设计(源码+文档+调试+基础修改+答疑)
vue.js·spring boot·后端