I’m having an issue using svelte.
I’m trying to map an object passed as a prop and then use it in an #each
block.
It works fine until I try to bind the element to the object using bind:this
. It causes an infinite update loop and freezes the page.
So I’m wondering if it’s me doing something wrong or an issue with svelte.
Here’s the code:
App.svelte
<script>
import InfiniteLoop from "./InfiniteLoop.svelte";
let data = [1, 2, 3];
</script>
<InfiniteLoop {data} />
InfiniteLoop.svelte
<script>
export let data;
$: mapped = data.map((v) => ({
value: v,
element: undefined
}));
</script>
{#each mapped as m}
<div>{m.value}</div>
<!-- Uncommenting this will freeze the page -->
<!-- <div bind:this={m.element}>{m.value}</div> -->
{/each}
Here’s the REPL: https://svelte.dev/repl/149e541b97c841028dbbcba13809d1c2?version=4.0.5
Making the reactive variable just a const stops the page from freezing, but doesn’t solve my issue.
2
Answers
This is a known issue in svelte, as the binding is changed it mutates the original array and while the reactive declaration should ignore it, it doesn’t.
For reference please loo at here
https://github.com/sveltejs/svelte/issues/4448
and
https://github.com/sveltejs/svelte/issues/7704
Some more cases when it breaks:
https://github.com/sveltejs/svelte/issues/4426
The solution would be to change to primitive types or raw variables, or perhaps considering using stores for your arrays/objects.
You could just use a action instead. Any dependencies (like the
value
) can be passed in.Alternatively, extract the contents of the
{#each}
to a separate component which gives you a new top level scope in which you can do anything independently from the rest of the data, e.g. update astyle
variable viasetInterval
and just pass that directly to thediv
.Or wrap the style calculation and interval logic in a store attached to the array, then the store’s value can be passed to the
style
attribute.Generally you should not need or use
bind:this
much.