Skip to content

Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node #2515

@kachurun

Description

@kachurun

Describe the bug

I'm creating a DND library on top of dnd-kit/dom and have run into this issue. By nature, sorting libraries use optimistic updates in the DOM tree to perform updates on the fly. Once complete, I need to sync the current DOM order with the order in my data. Sometimes this works well, but other times Solid tries to sort nodes that were already sorted by the optimistic DND update. In some cases, it even throws the error:
Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.

Your Example Website or App

Unexpected move:
https://playground.solidjs.com/anonymous/759847e3-477a-4a02-bd70-48d05d87a87e

Throw:
https://playground.solidjs.com/anonymous/4d15e0bf-5bbb-4784-bc77-b96000ccd884

Steps to Reproduce the Bug or Issue

Render the list of 5 elements: createSignal([1, 2, 3, 4, 5])
Move element 1 after 4 in the DOM.
Sync the order in the data: setItems([2, 3, 4, 1, 5])
→ Solid will reorder the items, so instead of the expected 2 3 4 1 5, you'll get 3 4 1 2 5.


Render the list of 5 elements: createSignal([1, 2, 3, 4, 5])
Move element 3 after 5 in the DOM.
Sync the order in the data: setItems([1, 2, 4, 5, 3])
→ Solid will throw an error, and you'll get 1 2 5 4.

Expected behavior

I fully understand the nature of SolidJS and why this happens, but it would be good to have some way to force the correct order of items in For without completely rerendering the whole list. Or at least, not throw an error in the second case.
I’ve tried using For/Index and Keyed from solid-primitives, but nothing helps.
The only two ways I've found to solve this are: restoring the original order of DOM items before calling setItems, which is tricky and unreliable; or completely rerendering the whole list, which is slow and also breaks transitions for the DND library.
I also tried to find a way to memoize DOM nodes after rendering to restore them when rerendering the list, but I didn’t succeed. Maybe someone knows a way to do this.

Screenshots or Videos

No response

Platform

  • OS: -
  • Browser: Any
  • Version: ^1.9

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions