I am making a simpe "email confirm" page.
It gets confirm key from URL, sends a POST request to API which returns true
or nothing.
If key is correct the API removes it from database and returns true
so the page can show success message:
// pages/confirm/[key].vue
<script setup>
const route = useRoute();
const key = route.params.key;
const confirmed = ref(false);
try
{
const result = await $fetch('/api/confirm', {
method: 'post',
body: { key: key },
});
confirmed.value = !!result;
} catch {}
</script>
<template>
<div v-if="confirmed">Email confirmed!</div>
</template>
The problem is when I open the page in browser with correct key passed in URL I only see "Email confirmed" message for a few milliseconds and then it disappears with "hydration mismatch" warning in console.
As far as I understand, Nuxt renders the page on server where the page has "Email confirmed" message. But after API call information about confrim keys gets deleted from database so when it comes to browser render it calls for API once again, this time it gets an empty response (because there is no such email confirm key anymore) and removes successs message.
How can I fix it?
Maybe there is a way to make only one API call or somehow save its result?
I am new to Nuxt and I really don’t know how to propely work with this "double rendering" thing…
2
Answers
The simplest way is specifing the
pages/confirm/[key].vue
as a CSR-page-component innuxt.config.ts
since the page is only rendered on client side, the
$fetch
will only execute in users’ browsersThe second way is to use
useLazyFetch
instead of$fetch
, also, you need to wrap the<div>
in the<client-only>
However, in my view, verifying the key on the client side may not be a good idea, since it may cause safety issues.
you may do this on the server side which I mean the nuxt server (not the
/api
server which may powered by PHP/Java/Go/etc)Change
$fetch
function touseFetch
composable – it is merely a wrapper around, but it automatically dedupes server/client API calls. Not only it will get you rid of the hydration mismatch, but it also improves your app performance.There was a nice example with an explanation by Daniel Kelly of VueSchool about this exact topic at this year’s NuxtNation conference – it starts at 3:35:00