solidjs / solid

A declarative, efficient, and flexible JavaScript library for building user interfaces.
https://solidjs.com
MIT License
32.47k stars 927 forks source link

JSX Element Variable Renders Only Once When Referenced Multiple Times #2216

Closed coderfreii closed 4 months ago

coderfreii commented 4 months ago

Describe the bug

A variable containing a JSX element is referenced multiple times within the render function, but it only renders once.

I checked the output code generated by the compiler, and the insert function in the runtime is indeed called the same number of times as the number of references. However, because the inserted variable is the same DOM node instance, only the first insertion takes effect, and all subsequent insertions do not have any effect. I am not sure if this is a mechanism or a bug, but this behavior can be quite confusing for users' code.

Your Example Website or App

https://playground.solidjs.com/anonymous/c5c35dc6-d42b-496d-8b4b-a21c87ccb13b

Steps to Reproduce the Bug or Issue

  1. Click the playground link above to check the rendered result.

Expected behavior

Each reference to the variable containing the JSX element should result in the element being rendered every time it is referenced.

Screenshots or Videos

No response

Platform

Additional context

No response

maciek50322 commented 4 months ago

It's by design. In Solidjs JSX element creates html element (unlike vdom element in react), and you can manipulate it directly. You can see it if you do

const foo = <div>child</div>;
foo.style.backgroundColor = "red";
console.log(foo);

And because it's simply html element it works like in vanilla js, so if you do

const div = document.createElement("div");
document.body.append(div);
document.body.append(div);

You would also see only 1 instance of div in your html (it doesn't append second time, because the element is already there). To have more divs, the more divs should be first created, so this works

const div1 = document.createElement("div");
document.body.append(div1);
const div2 = document.createElement("div");
document.body.append(div2);

Here you would see 2 elements in html.

But for your use case, if you want to create multiple elements in Solidjs, you can create factory function for elements

const foo = () => <div>child</div>;
return <div>
  parent {foo()} {foo()}
</div>

Each time foo() is called, new element is created and with jsx syntax it's appended where it should be. Or just extract this as component

function Foo() {
  return <div>child</div>;
}

function App() {
  return <div>
    parent 
    <Foo />
    <Foo />
  </div>;
}
coderfreii commented 4 months ago

Thanks for your answer, it clarified a lot of things.