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.
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.