T
TanStack3y ago
stormy-gold

Problem vue-query hooks can only be used inside setup() function.

Hi, I am working on a project in which some data of a user is intended to be fetched after a specific button is clicked. I defined an arrow function in composition API and it looks like the following:
<script setup lang="ts">
const fetchUserRelatedProgram = (uid: number) => {
return useQuery(["reviewerProgram", uid], async () => {
try {
return await api.getReviewerPrograms(uid);
} catch (e: any) {
if (e instanceof InvalidSessionError) {
console.error(
"Session has already expired while querying reviewerProgram"
);
router.push("/");
return;
}
}
});
};
</script>
<script setup lang="ts">
const fetchUserRelatedProgram = (uid: number) => {
return useQuery(["reviewerProgram", uid], async () => {
try {
return await api.getReviewerPrograms(uid);
} catch (e: any) {
if (e instanceof InvalidSessionError) {
console.error(
"Session has already expired while querying reviewerProgram"
);
router.push("/");
return;
}
}
});
};
</script>
I wrap useQuery inside the arrow function to pass variables , and the function is to be triggered by button via v-on. However, clicking the button only leads to the error message: Uncaught Error: vue-query hooks can only be used inside setup() function. So my questions are: 1. Is it prohibited to call useQuery in functions that are not immediately executed in Vue setup function? 2. Is there other workaround to pass variable into useQuery?
8 Replies
quickest-silver
quickest-silver3y ago
Hi. So you should use your query as const {data, refetch} = fetchUserRelatedPrograms(NUMBER VARIABLE); To avoid immediately calling query use enabled: boolean parameter, and then on click call refetch() P.s the best practice is to define your query function as custom hook
stormy-gold
stormy-goldOP3y ago
Could you further explain defining query function as custom hook?
quickest-silver
quickest-silver3y ago
//userQueries.ts // imports ... export const useUserRelatedProgramQuery = (uid: number) => useQuery(["reviewerProgram", uid], async () => { try { const {data} = await api.getReviewerPrograms(uid); return data; } catch (e: any) { if (e instanceof InvalidSessionError) { console.error( "Session has already expired while querying reviewerProgram" ); router.push("/"); } }}, { enabled: someCondition //another options }); Then use in vue // UserComponent.vue <script setup lang="ts"> import { useUserRelatedProgramQuery } from './userQueries.ts' const {data, refetch, etc...} = useUserRelatedProgramQuery(userUID) </script> <template> <button @click="refetch()"> Fetch user program</button> </template>
stormy-gold
stormy-goldOP3y ago
Thank you. It helps a lot!
quickest-silver
quickest-silver3y ago
You are welcome
stormy-gold
stormy-goldOP3y ago
This solution works on the condition that userID is fixed. However, it would still be a problem if I want to pass userID as a parameter that is changed at runtime. That’s why in my original question I wrap useQuery in an arrow function.
quickest-silver
quickest-silver3y ago
Use ref or computed for userID, in queryKey it must be ref as-is (without .value) and in your api call queryFn just unref or .value ID. //userQueries.ts // imports ... export const useUserRelatedProgramQuery = (uid: Ref<number>) => useQuery(["reviewerProgram", uid], async () => { try { const {data} = await api.getReviewerPrograms(uid.value); return data; } catch (e: any) { if (e instanceof InvalidSessionError) { console.error( "Session has already expired while querying reviewerProgram" ); router.push("/"); } }}, { enabled: someCondition //another options }); Then use in vue // UserComponent.vue <script setup lang="ts"> import { useUserRelatedProgramQuery } from './userQueries.ts' const userUID = ref() const {data, refetch, etc...} = useUserRelatedProgramQuery(userUID) </script> <template> <button @click="refetch()"> Fetch user program</button> </template>
stormy-gold
stormy-goldOP3y ago
Thanks!!!

Did you find this page helpful?