I have created pinia store as composition 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 component 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 composition 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.
2
Answers
I solved this by this code:
It made me realize this is not async-await problem, but it's related to the store. I still don't understand why the first approach didn't work, so any comments are welcome. Also, when I console.log(dashboardStore.widgets) I get
which I also don't understand why and how can I see it's actual value.
I guess you need await in your async function: