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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:26:19