Open TeyKey1 opened 1 year ago
My attempt to make an workaround in Svelte 5. In based on the fact that order of firing effects reflects the current component tree (though it may be not true in case of custom elements).
Thanks for sharing a hack @7nik.
The solution looks simple but is hard to understand. As the project grows, depending on the reactive state and $effect.pre()
might become challenging, error-prone, and hard to follow/debug. Also, the solution seems performance heavy in cases where the list of nodes is too many
It would be great if Svelte could provide an API to support iterating the children or any other solution that makes looping the children's references (or registering them) in sequence.
As the project grows, depending on the reactive state and
$effect.pre()
might become challenging, error-prone, and hard to follow/debug.
What do you mean? $effect.pre()
is used only once, and without a reactive state, your app won't be reactive.
Also, the solution seems performance heavy in cases where the list of nodes is too many
This is rather POC. It can be optimized to update only the subtree level where the change occurred. Here, if you have hundreds of elements on the same level, it's probably better to represent them as a single component that accepts an array (note, in this issue are discussed renderless components).
It would be great if Svelte could provide an API to support iterating the children or any other solution that makes looping the children's references (or registering them) in sequence.
Provide a use case where you indeed need this to convince the team to add this sooner.
First of all, I like your solution and it works really well. Thanks for sharing.
$effect.pre() is used only once, and without a reactive state
Isn't $effect.pre()
dependent on treeVersion
state, which rerenders on every invalidate
call? This means if we registered 100 nodes, this hook would get called 100 times (on invalidate) for each node, to ensure list.push()
adds node in sequence.
Provide a use case
AFAIK, any imperative ui-library that needs proper order to render nodes/components correctly will require this feature.
Rendering on Canvas requires us to pass commands in sequence to maintain the z-index of added nodes. The same goes with ThreeJS, but I recently learned that Three has support for the .renderOrder
property, which can help us for the time being. However, what if we need to calculate this order dynamically? It will be challenging to do with Svelte.
React provides Children APIs (personally I don't like that API), I think Svelte can provide a better API, maybe a rune that provides us feedback on mounted children.
Yeah, that implementation rebuilds the tree from scratch after any change. But calling all those render
s (or even a few of them) later is potentially a much heavier operation, and in the case of canvas, you have to call all of them unless you use multiple canvases.
Describe the problem
Various ways of how to iterate/get all children of a Svelte component have been discussed in #5381 or #4455. However, there does not seem to be a way to determine the current order of the children in svelte if the children are renderless. In case of children which render stuff to the DOM you can simply use the DOM-tree to infer the ordering. The same goes for virtual DOM frameworks, where you just use the virtual DOM.
The reason I need this information is that I'm currently converting an imperative HTML 5 2D canvas library into a declarative svelte component library using renderless components. The resulting usage would roughly look like this:
Ideally, the actual component order of the shapes in svelte would match the draw order on the canvas, so the user does not have to worry about doing the ordering manually but simply rely on the svelte-native way of ordering components. To achieve this, I need to be able to not only know the children of the Layer component but also their current order.
Describe the proposed solution
It would be nice if there was a way to determine the current order of components. I understand that this is very much a niche use case, but this is also the first time I truly ran into a limitation of Svelte. I've tried various things in the past days to achieve this but looking at the Svelte source I don't think it is currently possible to do any of this. If it is, please let me know how :)
Alternatives considered
A considered way to infer the order of components was to listen to the before/afterUpdate hooks and notify the parent component on each call (using stores). The parent component then saves the order of the incoming child notifications, which corresponds to the current child order. This works well enough for stuff inside each blocks apart from #7001 which I also observed. This way of inferring the order fails in more complex cases where if blocks are used. In cases where this if block's condition initializes to false, there is no way of knowing where it belongs in the current order once it gets mounted.
In my use case, the alternative is that the user has to manage ordering of the shapes manually and simply ignore svelte ordering for most parts. This unfortunately complicates things for the user quite a bit compared to other libraries using vue or react which can directly rely on the order of the components.
Importance
nice to have