I am experiencing a strange hydration behaviour in Vue 3 (Nuxt/SSR context). In my component, I have a reactive variable that initialises with a timestamp.
On the initial client-side render, the standard mustache interpolation {{ processedHtml }} updates to the client-side time correctly, but the content inside v-html stays stuck on the server-side value. Both only "sync up" once a subsequent reactive change occurs (e.g., via a setTimeout).
The Problem:
Server Renders: Both values show Server Time (e.g.,
12:00:00).Client Hydration:
{{ processedHtml }}updates to Client Time (12:00:01), butv-htmlremains12:00:00.After 2000ms: Both update to the new timestamp and are finally in sync.
Minimal reproducable component:
<template>
{{ processedHtml }}
<div v-html="processedHtml" class="prose max-w-none prose-a:text-blue-600 hover:prose-a:underline"></div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
const props = defineProps<{
node: any;
}>();
const nowDate = ref<string>(Date.now().toString());
setTimeout(() => {
nowDate.value = Date.now().toString();
}, (2000));
const processedHtml = computed(() => {
return <p>${nowDate.value}</p>;
});
</script>
I suspect Vue's hydration algorithm is skipping the v-html update because the root element tag matches, but I'm not sure why it differs from the mustache interpolation behavior.
How can I ensure v-html stays in sync with the client-side reactive state immediately upon hydration?