#SolidJS Stores + SortableJS - Weird update bug at runtime | but data is correct.

13 messages · Page 1 of 1 (latest)

tawdry sorrel
#

I'm not sure how to best explain it so here's a video~.

The code is actually pretty easy to follow (Thanks to SolidJS's stores primitive, it's amazing). I've learned a lot of best practices with Solid since then when I picked up SolidJS in May 2024. I'm running into another roadblock that's testing my knowledge.

Anyone know how to maybe fix this? Or what the reason is? I'm already using reconcile. I'm thinking it's because SortableJS seems to perform updates on the DOM elements outside of SolidJS's knowledge so maybe it's just what it is?

Here's a PR on my project if you want to play around with it: https://github.com/Blankeos/car-finance-calculator/pull/1/files

tawdry sorrel
#

Hmm interesting so it's actually the way I update.

  1. Previously: 🙁
  const { parentRef: sortableParentRef } = useSortable({
    onEnd: (newIndex, oldIndex) => {
      if (newIndex === oldIndex) return;
      const copy = unwrap(savedSummaries);
      arrayMoveMutable(copy, oldIndex, newIndex);
      setSavedSummaries(reconcile(copy));
    },
  });
  1. Fixes the update issue (by not using reconcile). ✅
    onEnd: (newIndex, oldIndex) => {
      if (newIndex === oldIndex) return;
      setSavedSummaries((_savedSummaries) => {
        const copy = structuredClone(_savedSummaries);
        const sorted = arrayMoveImmutable(copy, oldIndex, newIndex);
        return sorted;
      });
    },
  1. Interestingly this doesn't work: 🙁
    onEnd: (newIndex, oldIndex) => {
      if (newIndex === oldIndex) return;
      setSavedSummaries((_savedSummaries) => {
        const copy = _savedSummaries; // Might be because we're not using structuredClone
        const sorted = arrayMoveImmutable(copy, oldIndex, newIndex);
        return sorted;
      });
    },

2 is the best solution, but there's 1 last error I'm facing. Whenever I sort to the end of the list. I get this:

tawdry sorrel
#

Minimal Reproduction:

dire ingot
#

This is just my personal perspective so I could be entirely off base.

Why would you think that Sortable would work with Solid?

Solid has to own the DOM in order to manipulate it efficiently, it heavily relies on “that things are where it left them”. Sortable strikes me as a library that acts “as if it owns the DOM” and cursory inspection of the framework specific integrations seem to corroborate that, as they seem to give Sortable an intermediate, framework friendly abstraction to keep Sortable away from the DOM.

So from my perspective having both Solid and Sortable act as two masters for the same vanilla DOM is asking for trouble.

So I would be in this camp:

I'm thinking it's because SortableJS seems to perform updates on the DOM elements outside of SolidJS's knowledge so maybe it's just what it is?

That may also explain why there was so little response to the Sortable comments in the PR you referenced.

But as stated, that's just my take.

GitHub

Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required. - SortableJS/Sortable

GitHub

Vue 3 compatible drag-and-drop component based on Sortable.js - SortableJS/vue.draggable.next

viscid fulcrum
#

yeah, the way you're combining solid and sortablejs will not work as explained by peerrey

#

you might be able get around by actually resolving the nodes yourself and feeding them into a node that solid doesn't render but that requires the internal working of both libraries

dire ingot
#

Note: by using structuredClone you are depriving the store of referential stability of the unchanged elements thus forcing a full replacement of the DOM elements managed by the For.

Here is a variation of your example that preserves referential stability of the elements but that shows how hopelessly confused Solid is getting. For also supplies the index() signal that represents the reactive index position of the rendered item.

Drag the 4 above the 3.

It seems Sortable is swapping the elements and then Solid is swapping them back—but the index() reflects where Solid thinks the elements are in the list, i.e. that 4 is above 3.

Drag the 5 about the 4.

  • Based on the changes in counts (see console) Solid then moves 5 in front of 3.

So you end up with an index() sequence of 0,1,4,3,2 when it should always be 0,1,2,3,4.

https://playground.solidjs.com/anonymous/026a0143-3818-4983-a772-855011f031ae

viscid fulcrum
#

maybe you could disable solid rendering while sortable is active and still have anything downstream reactive

dire ingot
#

Using <For each={unwrap(counts)}> seems to stop Solid from moving the elements. Consequently index() is stuck with the intial order.

viscid fulcrum
#

i think the best approach is to put the nodes back in the order as solid knows it if you must actually use sortable of course

#

nope, only works for a few cases as solid rendering has it own array reconciliation algorithm