Improve SolidJS support
Fix for #671, #609 and some parts from #666
- Replace
<RangedFor>with native<For> - Memorize item render result
-
indexis now signal instead of value -
cachesupport
Original problem:
Also, I see, current implementation for SolidJS is broken at all:
- It is necessary to use
<For>instead of<RangedFor>(which is actually custom<Index>).- The result of rendering children must be memorized.
indexmust be a signal! The whole point of <For> is that it does not re-render the element when the position changes!Otherwise, we are now seeing problems:
- Current problem from the issue.
- When changing the data list, a full re-rendering of all elements in the list occurs, we can forget about performance... :(
Also this PR have breaking changes:
But I think it's justified.
Could you also introduce keepMounted, a list that accepts the indexes of the children it should keep mounted, even when offscreen?
This is a feature necessary to have sticky items, and it is already implemented in the react/vue variants.
@ArjixWasTaken It doesn't look too hard. I'll try adding keepMounted and reverse when the current PR is merged.
imo it is in the scope of this PR, would you accept a PR to ur PR if I were to make one?
A large PR is hard to review. It's better to split it into different PRs. I added cache to this PR only because it was reviewed earlier.
Released in 0.41.0. PR for keepMounted is also welcome!
well this sucks, why must the index be decoupled from the data it's accompanied by?
index must be a signal! The whole point of is that it does not re-render the element when the position changes!
how does it achieve that?
how does it achieve that?
@ArjixWasTaken This is standard SolidJS behavior: https://docs.solidjs.com/reference/components/for Here's an example: https://playground.solidjs.com/anonymous/f914193c-693f-43d4-9b5a-02aa6f864564
When the list changes, only index() gets updated — the previous components are not re-created.
I assume you're more of a React developer than a SolidJS one. This behavior is similar to how React works when using unique keys (which is, in fact, a requirement of this library).
In SolidJS, there’s no such thing as key, each uniq item is determined by the reference itself.
To make this work correctly:
- You should use
<For>instead offorEach/map(this done inside virtua). - When updating data, the array reference must change, but the individual items' references should remain the same. That is, don't recreate the objects — mutate the array structure, not its elements.
well this sucks, why must the index be decoupled from the data it's accompanied by?
Now virtua is fully compatible with SolidJS. Why did that upset you? o_O
In general, when using signals or createStore, this isn’t usually an issue.
However, some store libraries like solid-zustand or immer-based ones mutate both the array and its items when updating, which breaks this pattern.
That approach is incompatible with how SolidJS tracks changes and won't work correctly (causes unnecessary renders).
In such cases, it's common to separate the list (just an array of ids) from the actual data (stored in a Record<id, Item>).
However, this goes beyond the scope of this library.