[Bug?]: reading JSX.Element prop outside JSX or > 1 time causes SSR hydration mismatch errors
Duplicates
- [x] I have searched the existing issues
Latest version
- [x] I have tested the latest version
Current behavior 😯
Hydration fails if you read element prop outside JSX like
const BrokenTest = (p: { children?: JSXElement }) => {
console.log(p.children);
return <div/>;
};
or more than once like p.children && <div>{p.children}</div> or <Show ...> equivalent
However, if you use a pipe or IIFE where underlying component reads the (jsx.element) signal only once inside template, it works.
Example:
(() => {
const el = p.children;
return <div>{el && <div>{el}</div>}</div>
})()
or
{pipe(p.children, el => el && <div>{el}</div>}
I'm guessing SolidJs creates a hydration key on each read action and then fails to find it inside the DOM.
Another thing to note:
- this seems to cause issues when passed children contains an html element (
<div>hi</div>), but not if i just pass a string by itself
Expected behavior 🤔
hydration should work in all those cases
Steps to reproduce 🕹
stackblitz: https://codesandbox.io/p/devbox/423f4v
select any "not working" option and refresh the demo window -> see hydration error
Short example:
...
<Route href="/" component={() => <BrokenTest><div>boom</div></BrokenTest>} />
...
const BrokenTest = (p: { children?: JSXElement }) => {
console.log(p.children);
return <div/>;
}
// OR
const BrokenTest = (p: { children?: JSXElement }) => {
return <div>{p.children && <div>{p.children}</div>}</div>
}
Context 🔦
No response
Your environment 🌎
all latest:
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.3",
"@solidjs/start": "^1.2.0",
"solid-js": "^1.9.9",
Is there a github repo i can use to replicate this?
I feel this is intended behavior. I think you have to use the children helper.
https://docs.solidjs.com/reference/component-apis/children
@brenelz there's a stackblitz link you to project you can fork (top right corner): https://codesandbox.io/p/devbox/423f4v
I don't find this behavior intuitive. In my mind, when i pass <div/> as props.children or props.left (e.g. <Header left={<div/>}), the div should be created immediately and only once. Subsequent access through props.left should merely return the created element, not recreate it every time.
However, even assuming this behavior is correct, I still don't believe it should result in hydration errors. The div being console.logged is not rendered in a template and is absent from the resulting HTML, so why is it being hydrated?
P.S. I would also expect the <Show /> component to handle cases like this out of the box without needing for utilities. Seems like a very common use case that results in a confusing error
Using the children helper can temporarily solve this.