N
Nuxt5d ago
Ulrich

Reactivity with UseFetch

Hi i have a custom useFetch composable for fetching my data from an external API. In /location page, when the user arrive, a first fetch is made with filterOptions (a reactive object that can have empty string at start), this page has a Filter component that content filters of the page and update filterOptions object according to user preferences. I want to remove empty key in filterOptions when the request is been made without loosing reactivity(refetch when some of filterOptions change). I stuck on it. That's my files.
// composables/use-api.ts
import type {UseFetchOptions} from "nuxt/app";
export function useApi<T>(
url: string | (() => string),
options?: UseFetchOptions<T>,
) {
return useFetch(url,{
...options,
$fetch: useNuxtApp().$api as typeof $fetch,
})
}
// composables/use-api.ts
import type {UseFetchOptions} from "nuxt/app";
export function useApi<T>(
url: string | (() => string),
options?: UseFetchOptions<T>,
) {
return useFetch(url,{
...options,
$fetch: useNuxtApp().$api as typeof $fetch,
})
}
// plugins/api.ts
export default defineNuxtPlugin((nuxtApp) => {
const { token } = useAuth()
const runtimeConfig = useRuntimeConfig()
const api = $fetch.create({
baseURL: runtimeConfig.public.apiBaseUrl,
onRequest({ request, options, error }) {
if (token.value) {
const headers = options.headers ||= {}
if (Array.isArray(headers)) {
headers.push(['Authorization', `${token.value}`])
} else if (headers instanceof Headers) {
headers.set('Authorization', `${token.value}`)
} else {
headers.Authorization = `${token.value}`
}
}
},
async onResponseError({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
}
})
// Expose to useNuxtApp().$api
return {
provide: {
api
}
}
})
// plugins/api.ts
export default defineNuxtPlugin((nuxtApp) => {
const { token } = useAuth()
const runtimeConfig = useRuntimeConfig()
const api = $fetch.create({
baseURL: runtimeConfig.public.apiBaseUrl,
onRequest({ request, options, error }) {
if (token.value) {
const headers = options.headers ||= {}
if (Array.isArray(headers)) {
headers.push(['Authorization', `${token.value}`])
} else if (headers instanceof Headers) {
headers.set('Authorization', `${token.value}`)
} else {
headers.Authorization = `${token.value}`
}
}
},
async onResponseError({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
}
})
// Expose to useNuxtApp().$api
return {
provide: {
api
}
}
})
Thanks
5 Replies
kapa.ai
kapa.ai5d ago
Hi @Ulrich. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: Sorry @Ulrich, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
Ulrich
UlrichOP3d ago
Some help ?
Muhammad Mahmoud
You posted your custom $fetch and useFetch implementations. A snippet of using those in the Filters component could help more. But as I currently understand your question, you can create a computed variable (for example, refinedFilterOptions) that removes the empty values filterOptions and any other logic you want and pass that to the useApi composable. Whenver the value of refinedFilterOptions changes it will trigger re-fetching because its reactive.
Ulrich
UlrichOP2d ago
That's what i done, but i want to send each key in params, when i destructure the computed object, it loose reactivity, how can i send each key seperately in request body without loosing reactivity ?
const filterOptions = reactive({
typeAnnonce: "location",
typeBien: "",
lieu: "",
price: 0
})

// console.log({util})
const filteredOptions = computed(() => {
return Object.fromEntries(
Object.entries(filterOptions).filter(([key, value]) => {
return !(util.isString(value) && value === "");
}))
});

const {data: annoncesData, status} = await useApi("/annonces/allPublic", {
params: {
...filteredOptions,
limit: 9,
page: page
},
transform: data => {
return data.data
},
})
const filterOptions = reactive({
typeAnnonce: "location",
typeBien: "",
lieu: "",
price: 0
})

// console.log({util})
const filteredOptions = computed(() => {
return Object.fromEntries(
Object.entries(filterOptions).filter(([key, value]) => {
return !(util.isString(value) && value === "");
}))
});

const {data: annoncesData, status} = await useApi("/annonces/allPublic", {
params: {
...filteredOptions,
limit: 9,
page: page
},
transform: data => {
return data.data
},
})
Muhammad Mahmoud
Try using watch in useApi and pass filteredOptions to it.
const {data: annoncesData, status} = await useApi("/annonces/allPublic", {
params: {
...filteredOptions,
limit: 9,
page: page
},
transform: data => {
return data.data
},
watch: [filteredOptions], // <--- Try this
})
const {data: annoncesData, status} = await useApi("/annonces/allPublic", {
params: {
...filteredOptions,
limit: 9,
page: page
},
transform: data => {
return data.data
},
watch: [filteredOptions], // <--- Try this
})
Want results from more Discord servers?
Add your server