Search code examples
javascriptvue.jsnuxt.jsgrid-layoutusefetch

Multiple API requests sent from Pinia store


I have GridLayout which has one GridItem (imported from vue3-grid-layout). They are draggable and resizable. When I move or resize item (when it's finished, not during the change), this component (named Widget) emits to parent (named Candidates page) new values for position and size for all items. Parent component (Candidates page) has Save button, which, on click, calls save function which then, calls function from the store to send POST request to the API and update positions and sizes. This is how it's supposed to work, and this part works.

However, after I click Save button for the first time and then choose to edit grid again (not to go too much into logic here, but there's variable named editMode, which determines whether the grid will be resizable and draggable at the time or not), while I'm moving or resizing the grid item, the API requests are being sent non-stop. For moving, all of them fail (probably incorrect data), but for resizing they return 200 OK. I don't understand why are these requests being sent.

Here's how these components look like:

Widget component:

<grid-layout
 :layout.sync="layout"
 :col-num="colNum"
 :row-height="30"
 :is-draggable="editMode"
 :is-resizable="editMode"
 :vertical-compact="true"
 :use-css-transforms="true"
>
 <grid-item
  v-for="item in layout"
  :static="item.static"
  :x="item.x"
  :y="item.y"
  :w="item.w"
  :h="item.h"
  :i="item.i"
  :key="item.i"
  @resized="resizedEvent"
  @moved="movedEvent"
  style="touch-action: none"
 >
  <WidgetsExtended
   :edit-mode="editMode"
   :index="item.i"
  ></WidgetsExtended>
 </grid-item>
</grid-layout>

WidgetExtended has some table inside which is actually displayed in grid item. Not important for this context.

<script setup>
import { ref } from "vue";
import { GridItem, GridLayout } from "vue3-grid-layout-next";

const emit = defineEmits(["updateLayout"]);

const props = defineProps({
  editMode: {
    type: Boolean,
    required: false,
    default: false,
  },
});

const layout = ref([]);
const colNum = ref(12);

function movedEvent(i, newX, newY) {
  emit("updateLayout", layout.value);
}

function resizedEvent(i, newH, newW, newHPx, newWPx) {
  emit("updateLayout", layout.value);
}
</script>

Candidates page:

<template>
  <div>
    <Widgets
      :edit-mode="editMode"
      @updateLayout="updateLayout"
    ></Widgets>
    <IconsEdit v-if="!editMode" @edit="editMode = true" />
    <IconsSave v-if="editMode" @save="save" />
  </div>
</template>

<script setup>
import { useCandidatesStore } from "~/stores/candidates";

const candidatesStore = useCandidatesStore();

const editMode = ref(false);
const newLayout = ref([]);
// function from store which sends API request
const { saveCandidatesLayout } = candidatesStore;

function save() {
  editMode.value = false;
  saveCandidatesLayout(newLayout.value);
}

function updateLayout(updatedLayout) {
  newLayout.value = updatedLayout;
}
</script>

Candidates store:

import { defineStore } from "pinia";
import { useFetch } from "#app";
import { useAuthStore } from "./auth";

const baseUrl = import.meta.env.VITE_API_KEY + "/hr/";

export const useCandidatesStore = defineStore("candidates", () => {
  const authStore = useAuthStore();

  function saveCandidatesLayout(body) {
    return useFetch(baseUrl + "layout/candidates", {
      method: "POST",
      headers: {
        Accept: "application/json",
        Authorization: "Bearer " + authStore.token,
      },
      body: body,
      onResponse({ request, response, options }) {
        // this part gets called non-stop, I tried to log everywhere and this is only part 
        return response._data;
      },
      onResponseError({ request, response, options }) {
        throw showError({
          statusCode: 401,
          statusMessage: "Error: " + error,
          fatal: true,
        });
      },
    });
  }

  return {
    saveCandidatesLayout
  };
});

I even tried to check in dev tools (Network tab) where is the request sent from. It's unclear, it looks like it is from some library and that it has root in pointerMove -> move function. The initiator for these requests is ofetch.d438bb6f.mjs:206 (fetch).

The thing I don't understand is how can moving or resizing grid item directly make API request, when non of the functions related to it can do it.


Solution

  • I found the issue! Thanks to this post https://github.com/nuxt/nuxt/issues/15741 I realized that I was sending reactive property to useFetch body, and every time it changes, the request was resent. I just used JSON.stringify(body) and it fixed the issue.