skip to Main Content

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


  1. 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:

    <script>
      import Component from './Component.svelte';
        
        export let emails = ['[email protected]', '[email protected]'];
        $: set = new Set(emails)
    </script>
    
    {#each emails as email}
        <Component email={email} bind:set />
    {/each}
    

    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.

    Login or Signup to reply.
  2. I want to update the bound element’s style once every x milliseconds. I can’t invalidate all of the data to update the style since setting up the elements involves some expensive computation.

    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 a style variable via setInterval and just pass that directly to the div.

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search