最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to await async action from pinia composition API - Stack Overflow

programmeradmin2浏览0评论

I have created pinia store as position API (setup). I have loadWidgets async function which I want to await outside of store, and then get widgets property from store (after it's been populated). It seems like .then() doesn't do the work, it doesn't actually await for this function to be finished. I need some better approach to this, any modification would work.

Here's dashboard.js file (store) content:

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

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

export const useDashboardStore = defineStore("dashboard", () => {
  const authStore = useAuthStore();
  const { getToken } = authStore;

  const widgets = ref([]);
  const fetchedWidgets = ref(false);

  async function loadWidgets() {
    return useFetch(baseUrl + "/list/get", {
      headers: {
        Accept: "application/json",
        Authorization: "Bearer " + getToken,
      },
      onResponse({ request, response, options }) {
        widgets.value = response._data;
        fetchedWidgets.value = true;
      },
      onResponseError({ request, response, options }) {
        throw showError({
          statusCode: 401,
          statusMessage: "Error: - " + response._data,
          fatal: true,
        });
      },
    });
  }

  return {
    widgets,
    loadWidgets,
    fetchedWidgets,
  };
});

Here's my ponent script where I try to use this store:


<script setup>
import { ref } from "vue";
import { useDashboardStore } from "~/stores/dashboard";
import { useCandidatesStore } from "~/stores/candidates";

const props = defineProps({
  page: {
    type: String,
    required: true,
  },
});

const dashboardStore = useDashboardStore();
const candidatesStore = useCandidatesStore();

onMounted(async () => {
  await getWidgets().then((values) => {
    mapWidgetsData(values);
  });
});

const getWidgets = async () => {
  switch (props.page) {
    case "dashboard": {
      const { loadWidgets, widgets, fetchedWidgets } = dashboardStore;

      if (!fetchedWidgets) {
        return await loadWidgets().then(() => {
          return widgets.value;
        });
      }

      return widgets.value;
    }
    case "employees": {
      const { loadWidgets, widgets, fetchedWidgets } = candidatesStore;
     
      // Here will be done the same, just using diferent store. Not implemented yet
    }
  }
};

const mapWidgetsData = function (values) {
  var itemsData = values.data;
  layout.value = [];
  itemsData.forEach((value, key) => {
    let item = JSON.parse(value.position);
    item.i = value.id;
    item.type = value.type;
    layout.value.push(item);
  });
  index.value = values.last_index + 1;
};
</script>

I am using Nuxt 3, Vue 3 and Pinia store and position API. I tried wrapping this load function in Promise, but I always had some errors. With this code, the error I'm getting is Uncaught (in promise) TypeError: values is undefined because the return value of getWidgets function is undefined, because it doesn't wait for loadWidgets to finish API call and populate widgets field, but returns the widgets right away (I assume). I want it to wait for widgets to be populated with the value from response and then to continue execution.

I have created pinia store as position API (setup). I have loadWidgets async function which I want to await outside of store, and then get widgets property from store (after it's been populated). It seems like .then() doesn't do the work, it doesn't actually await for this function to be finished. I need some better approach to this, any modification would work.

Here's dashboard.js file (store) content:

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

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

export const useDashboardStore = defineStore("dashboard", () => {
  const authStore = useAuthStore();
  const { getToken } = authStore;

  const widgets = ref([]);
  const fetchedWidgets = ref(false);

  async function loadWidgets() {
    return useFetch(baseUrl + "/list/get", {
      headers: {
        Accept: "application/json",
        Authorization: "Bearer " + getToken,
      },
      onResponse({ request, response, options }) {
        widgets.value = response._data;
        fetchedWidgets.value = true;
      },
      onResponseError({ request, response, options }) {
        throw showError({
          statusCode: 401,
          statusMessage: "Error: - " + response._data,
          fatal: true,
        });
      },
    });
  }

  return {
    widgets,
    loadWidgets,
    fetchedWidgets,
  };
});

Here's my ponent script where I try to use this store:


<script setup>
import { ref } from "vue";
import { useDashboardStore } from "~/stores/dashboard";
import { useCandidatesStore } from "~/stores/candidates";

const props = defineProps({
  page: {
    type: String,
    required: true,
  },
});

const dashboardStore = useDashboardStore();
const candidatesStore = useCandidatesStore();

onMounted(async () => {
  await getWidgets().then((values) => {
    mapWidgetsData(values);
  });
});

const getWidgets = async () => {
  switch (props.page) {
    case "dashboard": {
      const { loadWidgets, widgets, fetchedWidgets } = dashboardStore;

      if (!fetchedWidgets) {
        return await loadWidgets().then(() => {
          return widgets.value;
        });
      }

      return widgets.value;
    }
    case "employees": {
      const { loadWidgets, widgets, fetchedWidgets } = candidatesStore;
     
      // Here will be done the same, just using diferent store. Not implemented yet
    }
  }
};

const mapWidgetsData = function (values) {
  var itemsData = values.data;
  layout.value = [];
  itemsData.forEach((value, key) => {
    let item = JSON.parse(value.position);
    item.i = value.id;
    item.type = value.type;
    layout.value.push(item);
  });
  index.value = values.last_index + 1;
};
</script>

I am using Nuxt 3, Vue 3 and Pinia store and position API. I tried wrapping this load function in Promise, but I always had some errors. With this code, the error I'm getting is Uncaught (in promise) TypeError: values is undefined because the return value of getWidgets function is undefined, because it doesn't wait for loadWidgets to finish API call and populate widgets field, but returns the widgets right away (I assume). I want it to wait for widgets to be populated with the value from response and then to continue execution.

Share Improve this question asked Aug 8, 2023 at 22:46 AleksandraAleksandra 1031 gold badge1 silver badge8 bronze badges 1
  • 1 you've probably confused yourself with await somePromise.then( .... ) ... and not returning what you think you're returning ... either use async/await OR use .then ... you hardly ever need to use .then inside an async function – Jaromanda X Commented Aug 8, 2023 at 22:49
Add a ment  | 

1 Answer 1

Reset to default 4

The issue here was that I was extracting the ref variables from the store the same way as functions, which is not allowed in Pinia, because then they lose reactivity. I should have accessed them like

dashboardStore.widgets

instead of

const { widgets } = dashboardStore;

The same for fetchedWidgets, it's bool variable.

发布评论

评论列表(0)

  1. 暂无评论