N
Nuxt2w ago
Hugo

Hydratation text mismatch on

Hello i have an issue i can't fix it. i have an hydratation mismatch on the component PartOfferCard when i want to display the dateStart Parent component where i get the datas
<script setup lang="ts">

import type { BlockFeatPremiumOffers } from './feat-premium-offers-types';
defineProps<{
data: BlockFeatPremiumOffers;
}>();


const baseURL = useRuntimeConfig().public.directusUrl
const { data: offers} = await useFetch(`${baseURL}/api/offers`,{
query:{
isPremium: true,
perPage: 9
}
})
</script>
<script lang="ts">
import '@splidejs/vue-splide/css';
import { Splide, SplideSlide } from '@splidejs/vue-splide';
export default defineComponent( {
components: {
Splide,
SplideSlide,
},
} );
</script>

<template>
<BlockContainer class="block-feat-premium-offers my-10 bg-secondary-100 lg:my-20">
<div v-for="(offer, index) in offers.data">
<PartsOfferCard :offer="offer" variant="premium"></PartsOfferCard>
</div>
</BlockContainer>
</template>
<script setup lang="ts">

import type { BlockFeatPremiumOffers } from './feat-premium-offers-types';
defineProps<{
data: BlockFeatPremiumOffers;
}>();


const baseURL = useRuntimeConfig().public.directusUrl
const { data: offers} = await useFetch(`${baseURL}/api/offers`,{
query:{
isPremium: true,
perPage: 9
}
})
</script>
<script lang="ts">
import '@splidejs/vue-splide/css';
import { Splide, SplideSlide } from '@splidejs/vue-splide';
export default defineComponent( {
components: {
Splide,
SplideSlide,
},
} );
</script>

<template>
<BlockContainer class="block-feat-premium-offers my-10 bg-secondary-100 lg:my-20">
<div v-for="(offer, index) in offers.data">
<PartsOfferCard :offer="offer" variant="premium"></PartsOfferCard>
</div>
</BlockContainer>
</template>
OfferCard Component
<script setup type="ts">
import { DateTime } from 'luxon';

const props = defineProps({
offer: {
type: undefined,
required: true,
},
variant: {
default: '',
validator: (value) => ['', 'premium'].includes(value),
},
})
const offer = computed(() => props.offer)
const variant = computed(() => props.variant)
const dateStart = computed(() => DateTime.fromISO(props.offer.date_start).toRelative())
</script>
<template>

<div class="aspect-square bg-white shadow-offer-card">
<p class="flex items-center gap-2 text-sm italic text-secondary">
{{dateStart}}
</p>
</div>
</template>
<script setup type="ts">
import { DateTime } from 'luxon';

const props = defineProps({
offer: {
type: undefined,
required: true,
},
variant: {
default: '',
validator: (value) => ['', 'premium'].includes(value),
},
})
const offer = computed(() => props.offer)
const variant = computed(() => props.variant)
const dateStart = computed(() => DateTime.fromISO(props.offer.date_start).toRelative())
</script>
<template>

<div class="aspect-square bg-white shadow-offer-card">
<p class="flex items-center gap-2 text-sm italic text-secondary">
{{dateStart}}
</p>
</div>
</template>
5 Replies
kapa.ai
kapa.ai2w ago
Hi @Hugo. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the information provided in your question and the knowledge sources available, it appears you're experiencing a hydration mismatch issue in a Nuxt application when displaying the dateStart in your PartOfferCard component. This type of issue often occurs when there's a difference between the server-side rendered content and the client-side rendered content. Let's analyze the potential causes and solutions: 1. Data Fetching Timing: The hydration mismatch might be occurring because the offers data is being fetched asynchronously in the parent component using useFetch. This means that the server and client might have different data at the time of rendering. 2. Date Formatting: You're using the luxon library to format the date, which could potentially produce different outputs on the server and client if there are timezone differences or if the current time changes between server and client rendering. To address this issue, you can try the following solutions: 1. Use useLazyFetch instead of useFetch: By using useLazyFetch, you ensure that the data is only fetched on the client-side, which can help avoid hydration mismatches. However, this approach sacrifices server-side rendering of the data.
const { data: offers } = await useLazyFetch(`${baseURL}/api/offers`, {
query: {
isPremium: true,
perPage: 9
}
})

const { data: offers } = await useLazyFetch(`${baseURL}/api/offers`, {
query: {
isPremium: true,
perPage: 9
}
})

Nuxt 3 Data Fetching (https://nuxt.com/docs/getting-started/data-fetching#usefetch) 2. Wrap the date display in a <client-only> component: This ensures that the date is only rendered on the client-side, avoiding hydration mismatches.
<template>
<div class="aspect-square bg-white shadow-offer-card">
<client-only>
<p class="flex items-center gap-2 text-sm italic text-secondary">
{{ dateStart }}
</p>
</client-only>
</div>
</template>

<template>
<div class="aspect-square bg-white shadow-offer-card">
<client-only>
<p class="flex items-center gap-2 text-sm italic text-secondary">
{{ dateStart }}
</p>
</client-only>
</div>
</template>

Nuxt Client-Only Component (https://nuxt.com/docs/api/components/client-only) 3. Use useAsyncData with a custom serializer: If you need to maintain server-side rendering, you can use useAsyncData with a custom serializer to ensure consistent date formatting between server and client.
import { DateTime } from 'luxon';

const { data: offers } = await useAsyncData('offers', () =>
$fetch(`${baseURL}/api/offers`, {
query: {
isPremium: true,
perPage: 9
}
}),
{
transform: (data) => {
return data.map(offer => ({
...offer,
date_start: DateTime.fromISO(offer.date_start).toRelative()
}))
}
}
)

import { DateTime } from 'luxon';

const { data: offers } = await useAsyncData('offers', () =>
$fetch(`${baseURL}/api/offers`, {
query: {
isPremium: true,
perPage: 9
}
}),
{
transform: (data) => {
return data.map(offer => ({
...offer,
date_start: DateTime.fromISO(offer.date_start).toRelative()
}))
}
}
)

Nuxt 3 Data Fetching (https://nuxt.com/docs/getting-started/data-fetching#useasyncdata) By implementing one of these solutions, you should be able to resolve the hydration mismatch issue. Remember to choose the approach that best fits your specific use case and performance requirements. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@122807566475591680> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Hugo
HugoOP2w ago
@kapa.ai the option 2 did the job, but what will be the impact on setting the date on client-side only
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I'm glad to hear that option 2 resolved your hydration mismatch issue. Let's discuss the impact of rendering the date on the client-side only using the <client-only> component. Using <client-only> to render the date on the client-side has both advantages and potential drawbacks: 1. SEO Impact: The main drawback is that the date won't be available for search engine crawlers or other services that rely on server-rendered content. This could potentially affect SEO if the date is considered important content for indexing Nuxt Rendering Modes (https://nuxt.com/docs/guide/concepts/rendering#universal-rendering). 2. Performance: There might be a slight delay in displaying the date, as it will only be rendered after the JavaScript has loaded and executed on the client side. This could result in a brief "flash" of content appearing Nuxt Rendering Modes (https://nuxt.com/docs/guide/concepts/rendering#client-side-rendering). 3. Server Load: On the positive side, by moving the date formatting to the client, you're reducing the computational load on the server, which could be beneficial if you have a large number of requests Nuxt Rendering Modes (https://nuxt.com/docs/guide/concepts/rendering#client-side-rendering). 4. Consistency: This approach ensures that the date is always rendered in the user's local timezone, which can provide a more personalized experience. 5. Hydration: As you've experienced, this solution effectively eliminates hydration mismatches related to date rendering Nuxt Client-Only Component (https://nuxt.com/docs/api/components/client-only). To mitigate some of these impacts, you could consider: 1. Using a placeholder: You can provide a fallback content that will be displayed on the server and during initial load:
<client-only>
<p class="flex items-center gap-2 text-sm italic text-secondary">
{{ dateStart }}
</p>
<template #fallback>
<p>Loading date...</p>
</template>
</client-only>

<client-only>
<p class="flex items-center gap-2 text-sm italic text-secondary">
{{ dateStart }}
</p>
<template #fallback>
<p>Loading date...</p>
</template>
</client-only>

This approach is mentioned in the Nuxt Client-Only Component (https://nuxt.com/docs/api/components/client-only) documentation. 2. Hybrid approach: If SEO is crucial, you could render a simplified date format on the server (e.g., ISO string) and then enhance it on the client side for better user experience. Remember, the treeshakeClientOnly experimental feature in Nuxt 3 helps optimize the server bundle by removing client-only component contents, which can help with performance Nuxt Experimental Features (https://nuxt.com/docs/guide/going-further/experimental-features#treeshakeclientonly). In summary, while using <client-only> solves your immediate issue, it's important to weigh these impacts against your application's specific requirements for SEO, performance, and user experience. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@122807566475591680> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Want results from more Discord servers?
Add your server