vite-plugin-vue
vite-plugin-vue copied to clipboard
Missing key in JSX when rendering conditionally unlike v-if
Related plugins
-
[ ] plugin-vue
-
[X] plugin-vue-jsx
Describe the bug
My colleague @tongxuanbao and I found an interesting issue when using JSX in Vue 3 for conditional rendering.
The symptom was that having this code:
<div>
{option === 1 && <MyCounter myprop="1" />}
{option === 2 && <MyCounter myprop="2" />}
</div>
would result in MyCounter preserving its internal state when option changes. It would receive updated prop as expected, however internal data/ref state inside of the component would not change, and when option changes there would be no unmounting and mounting.
The core issue stems from not having a key like <MyCounter key="1" myprop="1" />. We have inspected the compiled JavaScript code of vanilla Vue 3 using v-if with the compiled code of the latest Vue JSX app and the core difference was that vanilla Vue was adding key=0 and key=1 automatically, while the JSX plugin was not.
Here's the compiled vanilla Vue code:
t.value == 0 ? (ve(), gn(Xe(ar), { key: 0, label: "label1" })) : Xs("", !0),
t.value == 1 ? (ve(), gn(Xe(ar), { key: 1, label: "label2" })) : Xs("", !0),
And here's the compiled JSX code:
e.value === 0 && U(cr, { label: "label1" }, null),
e.value === 1 && U(cr, { label: "label2" }, null),
Reproduction
https://stackblitz.com/edit/vitejs-vite-ygezuc?file=src%2FApp.jsx
Steps to reproduce
npm install && npm run dev- Click on a button to increase counter 3 times
- Change the option from 0 to 1
- Expect to see internal counter state to be 0, but actually it will remain the same - 3; At the same time, props are updated so it says "Counter 1"
System Info
System:
OS: Linux 5.0 undefined
CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 0 Bytes / 0 Bytes
Shell: 1.0 - /bin/jsh
Binaries:
Node: 18.18.0 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 9.4.2 - /usr/local/bin/npm
pnpm: 8.10.5 - /usr/local/bin/pnpm
npmPackages:
@vitejs/plugin-vue: ^4.5.0 => 4.5.0
@vitejs/plugin-vue-jsx: ^3.1.0 => 3.1.0
vite: ^5.0.2 => 5.0.2
Used Package Manager
npm
Logs
No response
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [X] The provided reproduction is a minimal reproducible example of the bug.
I believe this is related to https://github.com/vuejs/core/issues/1587
In which this case was handled in the vue compiler core: https://github.com/vuejs/core/blob/2cece5ba1b9b254cface23096d17ed0e1910467d/packages/compiler-core/src/transforms/vIf.ts#L46-L57
a workaround
{option.value === 0 && <MyCounter key={0} label={'Counter 0'}></MyCounter>}
{option.value === 1 && <MyCounter key={1} label={'Counter 1'}></MyCounter>}