N
Nuxt2mo ago
Dalek

Nuxt keep infinitely sending request when using useFetch

Hello, I am wondering is it a bug or my code just wrong? Nuxt 3.17, node js v24.1.0 Server gets request as expected. Here is composable export const sanctumApi = async <T>(url:string, headers:Record<string, any>|null=null,opts:T|null=null) => { const xsrfToken = useCookie('XSRF-TOKEN') headers = { accept: 'application/json', ...headers } if (xsrfToken && xsrfToken.value !== null) { headers['X-XSRF-TOKEN'] = xsrfToken; } return useFetch(url, { headers:headers, retry:false, server: false, credentials: 'include', ...opts, }) }
3 Replies
kapa.ai
kapa.ai2mo ago
Hi @Dalek. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Your issue—Nuxt infinitely sending requests when using your custom composable wrapping useFetch—can be caused by how reactivity and composable usage are handled in Nuxt. Key Points from the Knowledge Sources 1. Reactivity in useFetch options:
If you pass reactive objects (like refs or reactive) to options such as headers or query, useFetch will re-run the request whenever those values change. This is similar to specifying them in the watch array, even if you don't explicitly do so. For example, if headers or any value inside it is reactive, any change will trigger a new request, potentially causing an infinite loop if the request itself changes the value again or if the value is unstable (e.g., a new object reference each render) see this explanation. 2. Custom useFetch wrappers:
When creating a custom wrapper for useFetch, you should not make the wrapper itself async or await useFetch inside the composable. Instead, return the result of useFetch directly. Awaiting inside the composable can break reactivity and cause unexpected behavior Nuxt docs: custom useFetch. 3. Reactive keys and infinite requests:
If you use a reactive value as a key or in options, and it changes on every render (for example, if you create a new object each time), useFetch will keep refetching. This can happen if you pass a new headers object on every call, as objects are compared by reference Upgrade guide: key change behavior. What’s likely wrong in your code - You are creating a new headers object every time the composable runs. If this composable is called in a component's setup function, it will create a new object on every render, which useFetch treats as a change, triggering a new request. - If any value in headers is a ref or reactive, and it changes, it will also trigger a new request. How to fix - Move the creation of the headers object outside the composable or memoize it so it doesn't change on every render. - Avoid passing reactive values directly in options unless you want useFetch to watch them. - Do not make your custom composable async or await useFetch inside it. #### Example Fix
// Do NOT make the composable async
export function sanctumApi<T>(url: string, headers: Record<string, any> = {}, opts: T = {} as T) {
const xsrfToken = useCookie('XSRF-TOKEN')
const staticHeaders = {
accept: 'application/json',
...headers,
...(xsrfToken.value ? { 'X-XSRF-TOKEN': xsrfToken.value } : {})
}
return useFetch(url, {
headers: staticHeaders,
retry: false,
server: false,
credentials: 'include',
...opts,
})
}
// Do NOT make the composable async
export function sanctumApi<T>(url: string, headers: Record<string, any> = {}, opts: T = {} as T) {
const xsrfToken = useCookie('XSRF-TOKEN')
const staticHeaders = {
accept: 'application/json',
...headers,
...(xsrfToken.value ? { 'X-XSRF-TOKEN': xsrfToken.value } : {})
}
return useFetch(url, {
headers: staticHeaders,
retry: false,
server: false,
credentials: 'include',
...opts,
})
}
- Note: xsrfToken.value is used to avoid passing a ref directly. - The composable is not async and does not await useFetch. For more details, see the Nuxt custom useFetch recipe and Stack Overflow discussion on useFetch reactivity. --- Summary:
Your infinite requests are likely due to passing a new headers object (or reactive values) to useFetch on every render. Make your headers static and avoid making your composable async or awaiting useFetch inside it. This should resolve the issue. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@341897947266416652> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Dalek
DalekOP2mo ago
that works

Did you find this page helpful?