N
Nuxt3w ago
w3cj

watchEffect vs effect (Hydration Error)

I recently solved a hydration error by switching from watchEffect in a pinia store to effect (from @vue/reactivity) - why are these treated differently in Nuxt? Is there a way to make sure watchEffect runs during SSR as well?
2 Replies
kapa.ai
kapa.ai3w ago
Hi @w3cj. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- The hydration error you experienced is related to how Nuxt handles server-side rendering (SSR) and client-side hydration. Let me explain why switching from watchEffect to effect solved your issue. Why the Hydration Error Occurred In Nuxt's universal rendering mode, your application runs twice - once on the server and once on the client during hydration. Hydration errors occur when there's a mismatch between what was rendered on the server and what is rendered on the client. When using watchEffect in a Pinia store, it can cause hydration mismatches because: 1. watchEffect may run at different times or with different results on the server versus the client 2. Side effects from watchEffect might modify store state differently between server and client renders As explained in a Stack Overflow post about hydration mismatches:
In Nuxt SSR the page is generated twice - first it is statically pre-rendered on server, then second time it is being "hydrated" with JavaScript features on client. But it works with the same data scope. [...] So it is different during the first time Vue is mounting on server and the second when mounting on client. And this causes hydration mismatch warning.
Stack Overflow Post Why effect Works Better The effect function from @vue/reactivity is more primitive and has different behavior than watchEffect. It runs immediately during both server-side rendering and client-side hydration, making it more consistent across environments. Making watchEffect Work with SSR If you want to use watchEffect in a Pinia store with Nuxt, consider these approaches: 1. Use callOnce: This utility ensures code runs only once during SSR and not during hydration:
await callOnce(() => {
// Your store action or side effect here
})
await callOnce(() => {
// Your store action or side effect here
})
As mentioned in the Nuxt documentation:
callOnce is useful in combination with the Pinia module to call store actions.
Call Once Documentation 2. Initialize state properly: Make sure your Pinia store is initialized the same way on both server and client:
// In your app.vue or a plugin
const store = useYourStore()

await callOnce(async () => {
await store.fetchData() // Your store action
})
// In your app.vue or a plugin
const store = useYourStore()

await callOnce(async () => {
await store.fetchData() // Your store action
})
3. Use useHydration: For advanced cases, you can use useHydration to control the hydration cycle:
useHydration(
'myStoreState',
() => myStore.getState(),
(data) => myStore.setState(data)
)
useHydration(
'myStoreState',
() => myStore.getState(),
(data) => myStore.setState(data)
)
Best Practices for Avoiding Hydration Errors 1. Avoid side effects in the root scope of components or stores 2. Use useState for SSR-friendly reactive state 3. For data fetching, use useAsyncData or useFetch which are designed to work with SSR 4. For Pinia stores, initialize them with callOnce to ensure consistency Remember that Vue lifecycle hooks like onBeforeMount and onMounted don't run during SSR, so they're safe places to put client-only code that won't cause hydration mismatches. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@339926319657779202> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?