N
Nuxt3mo ago
Doodie

Functions gets called twice.

I have a button calling a function using @click binding. In there i have a simple API call await $fetch("http://localhost:8080/") But that request gets sent twice during development. I understand its because it gets ran on the server and also the client. How do i make it only run on the client, or only on the server. but not both
2 Replies
kapa.ai
kapa.ai3mo ago
Hi @Doodie. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- In Nuxt’s universal rendering, code in component setup can run on both server and client, which can lead to “double” requests if you use $fetch there. But a click handler runs only in the browser after hydration. If you’re seeing two requests in development, common causes are: - You triggered one request on SSR (e.g., in setup via $fetch/useFetch) and another on click. - You used useFetch and then also manually executed again. - You hot-reloaded during dev. How to ensure the request only runs on the client: - Wrap the call in a client-only guard:
const onClick = async () => {
if (import.meta.client) {
await $fetch('<http://localhost:8080/'>)
}
}

const onClick = async () => {
if (import.meta.client) {
await $fetch('<http://localhost:8080/'>)
}
}

This ensures it never runs on the server. [Nuxt lifecycle] - If you use useFetch with immediate: false and call execute(), note that execute() will run regardless of server:false and can fire on SSR unless you guard it:
const { execute } = useFetch('/api/endpoint', { server: false, immediate: false })
const onClick = async () => {
if (import.meta.client) await execute()
}

const { execute } = useFetch('/api/endpoint', { server: false, immediate: false })
const onClick = async () => {
if (import.meta.client) await execute()
}

This is an acknowledged behavior; server:false only disables the initial automatic request, not execute(). [GitHub issue] - For UI that must render only on the client (e.g., depends on browser-only APIs), wrap it in <ClientOnly> or make the component a .client.vue to avoid any server-side run. [ClientOnly; Client components] General guidance: - Use useFetch/useAsyncData for data needed at render time to avoid double-fetch on hydration; they forward server-fetched data to the client. [Data fetching] - Use $fetch for user-triggered actions (like button clicks) that happen only in the browser. [Dollarfetch] If you truly want client-only fetching even when using useFetch, set server: false (and optionally lazy) and handle loading states:
const { status, data, execute } = useFetch('/api/endpoint', {
server: false,
lazy: true,
immediate: false
})
const { status, data, execute } = useFetch('/api/endpoint', {
server: false,
lazy: true,
immediate: false
})
Then call execute() inside an import.meta.client guard on click. [Lazy and client-only] ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@507856707628564493> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?