Why does my component only update in a dummy For loop?

The component works correctly in the For loop, but doesn't do anything on it's own.
<For each={[props.string]}>
{(t) => <Item content={t} />}
</For>
<For each={[props.string]}>
{(t) => <Item content={t} />}
</For>
<Item content={props.string} />
<Item content={props.string} />
The component itself doesn't seem to matter, it can be as simple as return props.content
8 Replies
REEEEE
REEEEE17h ago
How are you reading the prop? You can't do return props.content as it won't be reactive. It has to be read in jsx. So you can do return <> {props.content}</> to make it reactive
hyperknot
hyperknotOP17h ago
OK, I'll put it, but that part I just tried to make it too much minimal reproducible code sample. I'll make a bit more detailed one OK, it worked correctly with return <> {props.content}</>. So I went back and checked the original, function, which doesn't work:
export const StreamingAssistantMessage = (props: {
content: string
}) => {
const tokens = getMarkdownTokens(props.content)

return (
<div {...stylex.attrs(messageStyles.message, messageStyles.assistantMessage)}>
<div class="markdown-body">
<For each={tokens}>{(tok) => <MarkdownToken token={tok} />}</For>
</div>
</div>
)
}
export const StreamingAssistantMessage = (props: {
content: string
}) => {
const tokens = getMarkdownTokens(props.content)

return (
<div {...stylex.attrs(messageStyles.message, messageStyles.assistantMessage)}>
<div class="markdown-body">
<For each={tokens}>{(tok) => <MarkdownToken token={tok} />}</For>
</div>
</div>
)
}
It works by wrapping it in a createMemo:
export const StreamingAssistantMessage = (props: {
content: string
}) => {
const tokens = createMemo(() => {
return getMarkdownTokens(props.content)
})

return (
<div {...stylex.attrs(messageStyles.message, messageStyles.assistantMessage)}>
<div class="markdown-body">
<For each={tokens()}>{(tok) => <MarkdownToken token={tok} />}</For>
</div>
</div>
)
}
export const StreamingAssistantMessage = (props: {
content: string
}) => {
const tokens = createMemo(() => {
return getMarkdownTokens(props.content)
})

return (
<div {...stylex.attrs(messageStyles.message, messageStyles.assistantMessage)}>
<div class="markdown-body">
<For each={tokens()}>{(tok) => <MarkdownToken token={tok} />}</For>
</div>
</div>
)
}
Is there any way to say that one value is reactive, without using createMemo?
REEEEE
REEEEE17h ago
You could use a normal function too or inline getMarkdownTokens(props.content) into the each
hyperknot
hyperknotOP17h ago
so I just cannot use it outside of the JSX part? ok, inlining I get it, it works. can you explain the "You could use a normal function too" part?
REEEEE
REEEEE16h ago
You can do this
const tokens = createMemo(() => {
return getMarkdownTokens(props.content)
})
const tokens = createMemo(() => {
return getMarkdownTokens(props.content)
})
OR
const tokens = () => {
return getMarkdownTokens(props.content)
}
const tokens = () => {
return getMarkdownTokens(props.content)
}
to make the read to props.content reactive. Since solid components don't generally rerun, once you read the prop (like in your original use), it gets that value at the time of read and that's it. Only effects, memos, jsx, and functions (for the most part) are reactive. If you read props or any reactive value in the body of the component it won't be reactive
hyperknot
hyperknotOP16h ago
Great, thanks! So no need for createEffect or createRenderEffect for this?
REEEEE
REEEEE16h ago
Nope
hyperknot
hyperknotOP16h ago
Thanks!

Did you find this page helpful?