solid-start
solid-start copied to clipboard
<Title /> does not support reactive values?
<Title>
{appState.title
? `${appState.title} - RedditLattice`
: `RedditLattice`}
</Title>
This in my root.tsx doesn't work and I have confirmed with a console log in a createEffect that appState.title does trigger a signal to change.
Relevant Source Code: https://github.com/vanillacode314/redditlattice/blob/solidjs/src/root.tsx
Hey @vanillacode314! In Solid, you are unable to use ternary operators to express conditional rendering blocks. You need to use the Show
component in Solid to do this. The reason ternary operators don't work like they do in React is because Solid uses a fine-grained, component-based reactivity system. Because of this, components in Solid only render ONCE, and only createEffect
(and other special primitives) run after the component is mounted. These special components (like Show
and For
) cause conditional render changes after the initial render/mount of the component by using the Solid compiler that communicates with the real DOM directly.
You can use it like so:
import { Show } from "solid-js";
<Title>
<Show when={appState.title} fallback={`RedditLattice`}>
`${appState.title} - RedditLattice`
</Show>
</Title>
The when
attribute will render the fallback
attribute content if a falsy value is returned.
From the solidjs tutorial
Solid's compiler is smart enough to optimally handle ternaries (a ? b : c) and boolean expressions (a && b).
Plus replacing it with <Show>
still doesn't work
From the solidjs tutorial
Solid's compiler is smart enough to optimally handle ternaries (a ? b : c) and boolean expressions (a && b).
Plus replacing it with
<Show>
still doesn't work
Using a ternary definitely wouldn't work. Ternaries are in the form of a Javascript expression. There is absolutely zero way that Solid's compiler can handle that when the component only runs through the JSX and converts them into real DOM nodes once.
What happens when you try to use the Show
component?
What happens when you try to use the
Show
component?
It only shows what the initial state of appState.title
would show, this is the exact behaviour as ternary
@vanillacode314 - Scratch that. I think the culprit is that you are setting the Title
in the root. Because Solid Start is an SPA by default, the root.tsx
is used throughout your entire application, and no page reloads occur on route navigation. Try moving the Title
into each route file instead.
e.g.
routes/r/[subreddit].tsx
<Title>{appState.title}</Title> // you know that a title will be set based on the subreddit so this should be fine.
then you can set the fallback to apply to all other routes in root.tsx
if you want.
<Title>RedditLattice</Title>
That's what I tried but I believe this is another bug with solid-start right now that children <Title>
do not override root.tsx <Title>
Ah, in that case, I think you will need to wait for a fix. I don't believe there is another way to do it. I haven't really played around with Solid Start too much recently so I didn't even know this was a bug. Have you filed an issue/has an issue already been filed for this?
Found another weird thing
<Show when={appState.title} keyed>
{(title) => <Title>{title} - RedditLattice</Title>}
</Show>
This works but this only shows fallback
<Show when={appState.title} keyed fallback={<div>Loading</div>}>
{(title) => <Title>{title} - RedditLattice</Title>}
</Show>
Found another weird thing
<Show when={appState.title} keyed> {(title) => <Title>{title} - RedditLattice</Title>} </Show>
This works but this only shows fallback
<Show when={appState.title} keyed fallback={<div>Loading</div>}> {(title) => <Title>{title} - RedditLattice</Title>} </Show>
Oh, try making the when
attribute a strictly boolean expression. Try appState.title !== ""
or something like that (that is what I believe the default is in your application). I also forgot about the new keyed
attribute on Show
and For
.
yeah already tried that doesn't work
Yeah this is probably a bug, the code you wrote makes sense and should work, will explore the cause and get back
Hi, not 100% if this bug relates to the following, however encountered something similar
The <Title /> component playing well with SSR, but when client side navigation takes over, the Title tag gets flushed and renders empty.
Looked into the solid-meta repo but I feel like that part is playing out well, almost feel like the solid-router or something on the solid-start client side of things not playing well with the MetaProvider.
Lil examples of the bug
- stackblitz demo -> toggle back and forth from Index and other to checkout the bug
- repo
Hope it can be of help
Edit: after looking into this a bit closer, it seems like I had a bug in my own code, and the first behavior I described doesn't really happen. It's working fine. The other bug (empty tag) does still happen under some circumstances.
Hi, ~I've also run into this bug, <Title />
just doesn't behave as other head tags would (e.g. Meta
, where the lowest tag "wins" and replaces any previous ones), which is unexpected~, plus I've also run into empty <title>
on client-side navigation as @gcavanunez shared.
Also, I'm fairly new to Solid so I might be confused, but my understanding is that anything inside of a JSX expression is reactive, as JSX expressions get essentially compiled to "smart" createEffect
-like calls, so a ternary (or absolutely any JavaScript expression that correctly uses signal or store accessors) should work, without the need for Show
, although it's also my understanding that Show
has some advantages that I don't remember right now over certain plain JS conditional expressions, iirc.
In conclusion, there's definitely something broken with Title
in need of a bug fix, I've confirmed this in my blog :P
Yeah you are probably right about the bug.. and you are right about your assumption about the JSX. Ternaries are reactive. And Show
basically is slightly more optimal where it will avoid recreating dom elements if it doesn thave to.
fixed upstream in @solidjs/meta