Pinia存储触发重复API请求:Vue3 GridLayout拖拽调整异常
问题分析与解决
问题现象
使用vue3-grid-layout的拖拽调整功能,正常流程为:拖拽/调整后子组件emit布局更新,父组件点击保存按钮才调用Pinia的saveCandidatesLayout发送POST请求。但首次保存后再次进入编辑模式,拖拽或调整网格项时会持续触发API请求:拖拽时请求失败,调整大小时请求返回200 OK,而代码中并没有在拖拽/调整时直接调用API的逻辑。
根因
问题出在Pinia中错误使用了Nuxt的useFetch函数:
useFetch是Nuxt专为组件/页面设计的响应式数据获取函数,它会自动追踪所有响应式依赖(比如authStore.token、传入的body参数对应的响应式数据newLayout)。- 首次保存后,
newLayout是响应式ref,当拖拽调整时newLayout实时更新,useFetch会认为依赖发生变化,自动重新执行请求,导致拖拽过程中不断发起API调用。 - 拖拽时请求失败是因为布局还在实时变化,传递的body数据可能不完整或不符合接口校验;调整大小时布局稳定,所以返回200。
解决方案
1. 替换useFetch为$fetch
Pinia中不适合用useFetch(它的响应式追踪机制会导致意外的重复请求),换成Nuxt提供的普通$fetch函数,手动处理异步请求:
修改Pinia store代码:
import { defineStore } from "pinia"; import { $fetch } from "#app"; // 导入$fetch import { useAuthStore } from "./auth"; const baseUrl = import.meta.env.VITE_API_KEY + "/hr/"; export const useCandidatesStore = defineStore("candidates", () => { const authStore = useAuthStore(); // 改为async函数,用$fetch手动发起请求 async function saveCandidatesLayout(body) { try { // 深拷贝body,避免后续响应式数据变化影响请求参数 const requestBody = JSON.parse(JSON.stringify(body)); const response = await $fetch(baseUrl + "layout/candidates", { method: "POST", headers: { Accept: "application/json", Authorization: "Bearer " + authStore.token, // 直接取当前token值,不追踪响应式 }, body: requestBody, }); return response; } catch (error) { throw showError({ statusCode: error.response?.status || 401, statusMessage: `Error: ${error.message}`, fatal: true, }); } } return { saveCandidatesLayout }; });
2. 优化父组件的保存逻辑
调用保存函数时深拷贝布局数据,避免响应式引用导致的意外:
修改Candidates页面的save函数:
async function save() { editMode.value = false; // 深拷贝布局,确保传递给接口的是静态数据 await saveCandidatesLayout(JSON.parse(JSON.stringify(newLayout.value))); }
3. 优化子组件的emit逻辑
避免直接传递响应式引用,传递副本:
修改Widget组件的事件函数:
function movedEvent(i, newX, newY) { // 传递布局副本,避免父组件直接引用子组件的响应式数据 emit("updateLayout", [...layout.value]); } function resizedEvent(i, newH, newW, newHPx, newWPx) { emit("updateLayout", [...layout.value]); }
验证效果
修改后,再次进入编辑模式拖拽/调整网格项时,不会触发API请求,只有点击保存按钮时才会调用saveCandidatesLayout发送POST请求,符合预期流程。
内容的提问来源于stack exchange,提问作者Aleksandra
相关产品推荐
相关产品推荐

