Very strange bug in v-if and v-else !!
Vue version
3.3.4
Link to minimal reproduction
https://codesandbox.io/p/sandbox/epic-driscoll-dkznwy
Steps to reproduce
What is expected?
What is actually happening?
System Info
System:
OS: Linux 6.5 Arch Linux
CPU: (4) x64 Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz
Memory: 1.62 GB / 7.64 GB
Container: Yes
Shell: 5.9 - /usr/bin/zsh
Binaries:
Node: 20.8.0 - /usr/bin/node
Yarn: 1.22.19 - /usr/bin/yarn
npm: 10.1.0 - /usr/bin/npm
Browsers:
Brave Browser: 114.1.52.126
Any additional comments?
https://github.com/vuejs/core/assets/53816722/60b3d727-c345-4ae8-8b76-4a01a87453dc
Explain @yyx990803 ...
Please provide a minimal reproduction (no Nuxt and other external libraries) and take the time to describe your issue.
I think he wants to use Vue events like @click
inside the v-if
and v-else
block
@amirhossein-fzl See this playground, Also this is not the best practice to do something like this
SFC playground
for Icons use @iconify/tailwind
(pure css icons) or @iconify/vue
(Vue icon component) or @iconify-icon
(Web component) instead
The root of your issue is that HTML inserted via v-html
is not part of the diff-check during hydration (nor is is diffed during rendering).
So when the server renders a different icon than the client (which happens here as the server has no knowledge of the user's previously chosen dark/light mode preference), that goes unnoticed during hydration.
A simple solution would be to only render the icon client-side, as the state coming from the server would be wrong 50% of the time anyway. I believe nuxt provides a handy <ClientOnly>
wrapper component for that.
This is happening because the content rendered on the server-side with Nuxt is not what is initially rendered on the client-side.
Since your component for the switch uses useDark()
which in turns uses localStorage, it will always be light mode on the server and dark mode on the client (if it was selected).
You may, therefore, use <ClientOnly />
component to wrap this component, since server-side rendering it doesn't make sense anyway since it is dealing with a client-side concern.
This is not a bug with Vue or Nuxt.
I read all your comments and I think <ClientOnly />
is the answer in Nuxt. Although this is related to Next, I changed my project to vue and vite...
A ClientOnly Component is pretty simple, basically render the slot only after mounted:
So with that as a more general solution, I think I can close this.