Hard to move elements around using solid-js, insertExpression isn't fully DOM aware
Describe the bug
When wanting to only create two components once, but then switching them around in the DOM (wrapping and unwrapping them), solid-js doesn't really play nicely.
According to a discord conversation this isn't intended behavior, so here's a bug report.
Why do I want to do this? For switching between desktop and mobile layouts I don't see a reason to rerender big components and all their children just to wrap/unwrap them in a div.
Your Example Website or App
https://playground.solidjs.com/anonymous/30690d0e-bff5-4cd5-9309-a847e3b08683
Steps to Reproduce the Bug or Issue
Version 1: Definitely a bug (crashes)
If you don't deem this misusing solid it's probably a bug:
- Go to https://playground.solidjs.com/anonymous/4d71a9de-a5b7-463b-8718-53e87d9ef5df
- Hit the button
Uncaught DOMException: Failed to execute 'replaceChild' on 'Node': The new child element contains the parent.
From the error message, I suspect this could be avoided by using element.replaceWith or another one of the new DOM manipulation functions but I'm not sure (and I understand they are probably slower)
Version 2: Doesn't work as expected
This could be interpreted as expected behavior because there's no error but I'd still really love if this worked:
- Go to https://playground.solidjs.com/anonymous/1fe54bd3-2819-4a79-8bd9-bdaa7304d143
- Hit the button
- Elements disappear
Expected behavior
In example 1: No crash, element is moved
In example 2: Elements don't disappear, are moved instead
Screenshots or Videos
No response
Platform
- OS: macOS 14.2.1 (23C71)
- Browser: Chrome 120.0.6099.199 (Official Build) (arm64) , firefox 122.0b8
Additional context
No response
I see. These are scenarios where you are keeping a DOM reference, and Solid thinks it knows where it was inserted, but when we get Solid to insert somewhere it is no longer where Solid thinks. This is the kind of issue I'd like to fix if it isn't prohibitive. The challenge is I imagine stuff not being where we expect could have a multitude of possible issues, but trying to fix these should have no impact on people not using these patterns accept if there is some some small performance considerations.
In version 2 the bug is here: https://github.com/ryansolid/dom-expressions/blob/f691a482cea35336e7206759f0e8d2322f9371dd/packages/dom-expressions/src/reconcile.js#L72
What happens is that here
The insert call that was done here is wrongly undone
(The two elements in a are now children of the two elements in b respectively)
related:
- https://playground.solidjs.com/anonymous/1cc13580-7844-439e-ba93-fcab4e030910
- https://discord.com/channels/722131463138705510/1217034387938607145