N
Nuxt4d ago
Kyllian

Hydratation mismatch when using lazyFetch

This piece of code gives me a hydratation mismatch, when removing the for loop that displays the users it's gone.
<script lang="ts" setup>
import type { IUser } from '~/models/user';


definePageMeta({
layout: 'panel'
})

if (!(await allows(editUsers))) {
navigateTo('/panel')
}

const { data, status } = useLazyFetch<{ users: IUser[] }>('/api/v2/users/all', {
server: false
});

const onSearch = (query: string) => {
console.log("onSearch", query)
}

const onAdd = () => {
console.log("onAdd")
}
</script>

<template>
<NuxtLayout class="flex">
<PanelBarsEditBar title="Users" @search="onSearch" @add="onAdd"
:breadcrumb="{ text: 'Dashboard', href: '/panel' }" :bulk-actions="[
{ name: 'Delete', action: () => console.log('delete') }
]" :search="true" />
<div v-if="status === 'pending'">
<p>pending...</p>
</div>
<template v-else-if="data && data.users">
<div v-for="theUser in data.users" :key="theUser.username">
{{ theUser.username }}
</div>
</template>
</NuxtLayout>
</template>
<script lang="ts" setup>
import type { IUser } from '~/models/user';


definePageMeta({
layout: 'panel'
})

if (!(await allows(editUsers))) {
navigateTo('/panel')
}

const { data, status } = useLazyFetch<{ users: IUser[] }>('/api/v2/users/all', {
server: false
});

const onSearch = (query: string) => {
console.log("onSearch", query)
}

const onAdd = () => {
console.log("onAdd")
}
</script>

<template>
<NuxtLayout class="flex">
<PanelBarsEditBar title="Users" @search="onSearch" @add="onAdd"
:breadcrumb="{ text: 'Dashboard', href: '/panel' }" :bulk-actions="[
{ name: 'Delete', action: () => console.log('delete') }
]" :search="true" />
<div v-if="status === 'pending'">
<p>pending...</p>
</div>
<template v-else-if="data && data.users">
<div v-for="theUser in data.users" :key="theUser.username">
{{ theUser.username }}
</div>
</template>
</NuxtLayout>
</template>
9 Replies
kapa.ai
kapa.ai4d ago
Hi @Kyllian. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- The hydration mismatch issue you're experiencing when using useLazyFetch could be related to how data is being handled between the server and client. When using useLazyFetch, it's important to handle the pending state properly, as the data may not be immediately available on client-side navigation. Here are a few things to consider: 1. Ensure Proper Handling of Pending State: Since useLazyFetch triggers navigation before the data is fully fetched, you need to ensure that your template properly handles the pending state. This is crucial to avoid rendering issues that can lead to hydration mismatches. 2. Client-Only Fetching: You've set server: false, which means the data fetching will only occur on the client side. This can lead to a situation where the initial server-rendered HTML does not match the client-rendered HTML if the data is not yet available. Make sure your template accounts for this by showing a loading state until the data is ready. 3. Key Usage in v-for: Ensure that the key used in the v-for loop is unique and consistent. In your case, using theUser.username should be fine as long as usernames are unique. Here's a reference to the relevant documentation on useLazyFetch and handling pending states: useLazyFetch Documentation. If the issue persists, consider checking if there are any discrepancies in how the data is structured or if there are any side effects in your component logic that might affect the rendering process. For more detailed guidance, you can refer to the Nuxt Data Fetching Documentation which provides insights into handling lazy data fetching and client-only fetching scenarios. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@166602211780984832> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Kyllian
KyllianOP4d ago
@kapa.ai when using lazyFetch without the server: false, it never displays the pending state to the client and simply awaits the request. I want it to show the pending stat
kapa.ai
kapa.ai4d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- When using useLazyFetch without setting server: false, the data fetching will occur on both the server and client. This means that during server-side rendering, the data is fetched and the HTML is rendered with the data already present, so the client never sees the pending state. To ensure that the pending state is displayed to the client, you can set server: false to make the data fetching client-only. This way, the data will not be fetched until after the initial server-rendered HTML is sent to the client, allowing you to display a loading state while the data is being fetched. Here's how you can modify your code to achieve this:
<script lang="ts" setup>
import type { IUser } from '~/models/user';

definePageMeta({
layout: 'panel'
})

if (!(await allows(editUsers))) {
navigateTo('/panel')
}

const { data, status } = useLazyFetch<{ users: IUser[] }>('/api/v2/users/all', {
server: false // Ensures fetching is client-only
});

const onSearch = (query: string) => {
console.log("onSearch", query)
}

const onAdd = () => {
console.log("onAdd")
}
</script>

<template>
<NuxtLayout class="flex">
<PanelBarsEditBar title="Users" @search="onSearch" @add="onAdd"
:breadcrumb="{ text: 'Dashboard', href: '/panel' }" :bulk-actions="[
{ name: 'Delete', action: () => console.log('delete') }
]" :search="true" />
<div v-if="status === 'pending'">
<p>pending...</p>
</div>
<template v-else-if="data && data.users">
<div v-for="theUser in data.users" :key="theUser.username">
{{ theUser.username }}
</div>
</template>
</NuxtLayout>
</template>
<script lang="ts" setup>
import type { IUser } from '~/models/user';

definePageMeta({
layout: 'panel'
})

if (!(await allows(editUsers))) {
navigateTo('/panel')
}

const { data, status } = useLazyFetch<{ users: IUser[] }>('/api/v2/users/all', {
server: false // Ensures fetching is client-only
});

const onSearch = (query: string) => {
console.log("onSearch", query)
}

const onAdd = () => {
console.log("onAdd")
}
</script>

<template>
<NuxtLayout class="flex">
<PanelBarsEditBar title="Users" @search="onSearch" @add="onAdd"
:breadcrumb="{ text: 'Dashboard', href: '/panel' }" :bulk-actions="[
{ name: 'Delete', action: () => console.log('delete') }
]" :search="true" />
<div v-if="status === 'pending'">
<p>pending...</p>
</div>
<template v-else-if="data && data.users">
<div v-for="theUser in data.users" :key="theUser.username">
{{ theUser.username }}
</div>
</template>
</NuxtLayout>
</template>
By setting server: false, the data fetching will only occur on the client, allowing you to display the pending state while the data is being fetched. For more information, you can refer to the Nuxt Data Fetching Documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@166602211780984832> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Kyllian
KyllianOP4d ago
@kapa.ai yes, but as you said a minute ago, this causes a hydratation mismatch
kapa.ai
kapa.ai4d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- To address the hydration mismatch issue while still displaying a pending state, you can use a combination of client-only fetching and proper handling of the loading state. Here’s a strategy you can follow: 1. Client-Only Fetching: By setting server: false, you ensure that the data is fetched only on the client side. This allows you to show a loading state initially. 2. Use <client-only> Component: Wrap the part of your template that depends on the fetched data with the <client-only> component. This ensures that the component is only rendered on the client side, preventing hydration mismatches. Here’s how you can implement this:
<script lang="ts" setup>
import type { IUser } from '~/models/user';

definePageMeta({
layout: 'panel'
})

if (!(await allows(editUsers))) {
navigateTo('/panel')
}

const { data, status } = useLazyFetch<{ users: IUser[] }>('/api/v2/users/all', {
server: false // Ensures fetching is client-only
});

const onSearch = (query: string) => {
console.log("onSearch", query)
}

const onAdd = () => {
console.log("onAdd")
}
</script>

<template>
<NuxtLayout class="flex">
<PanelBarsEditBar title="Users" @search="onSearch" @add="onAdd"
:breadcrumb="{ text: 'Dashboard', href: '/panel' }" :bulk-actions="[
{ name: 'Delete', action: () => console.log('delete') }
]" :search="true" />
<client-only>
<div v-if="status === 'pending'">
<p>pending...</p>
</div>
<template v-else-if="data && data.users">
<div v-for="theUser in data.users" :key="theUser.username">
{{ theUser.username }}
</div>
</template>
</client-only>
</NuxtLayout>
</template>
<script lang="ts" setup>
import type { IUser } from '~/models/user';

definePageMeta({
layout: 'panel'
})

if (!(await allows(editUsers))) {
navigateTo('/panel')
}

const { data, status } = useLazyFetch<{ users: IUser[] }>('/api/v2/users/all', {
server: false // Ensures fetching is client-only
});

const onSearch = (query: string) => {
console.log("onSearch", query)
}

const onAdd = () => {
console.log("onAdd")
}
</script>

<template>
<NuxtLayout class="flex">
<PanelBarsEditBar title="Users" @search="onSearch" @add="onAdd"
:breadcrumb="{ text: 'Dashboard', href: '/panel' }" :bulk-actions="[
{ name: 'Delete', action: () => console.log('delete') }
]" :search="true" />
<client-only>
<div v-if="status === 'pending'">
<p>pending...</p>
</div>
<template v-else-if="data && data.users">
<div v-for="theUser in data.users" :key="theUser.username">
{{ theUser.username }}
</div>
</template>
</client-only>
</NuxtLayout>
</template>
By using <client-only>, you ensure that the component rendering the user data is only processed on the client side, which should help prevent hydration mismatches while still allowing you to display a loading state. For more details, you can refer to the Nuxt Client-Only Component Documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@166602211780984832> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Kyllian
KyllianOP4d ago
aye w

Did you find this page helpful?