javascriptstatejavascript-objectssvelte

Deleting keys from object in Svelte component state


I have a simple object in state, string -> objects. My UI renders the keys and values in a loop. Each object has a delete button. On click, I want to delete keys (or set them to undefined) such that the UI updates.

This page in the Svelte tutorial says:

A simple rule of thumb: the name of the updated variable must appear on the left hand side of the assignment. For example this...

const obj = { foo: { bar: 1 } };
const foo = obj.foo;
foo.bar = 2;

...won't trigger reactivity on obj.foo.bar, unless you follow it up with obj = obj.

Sure enough, if I handle the click like:

{#each Object.entries(objInState) as [key, value]}
  {value}
  <button on:click={_ => delete objInState[key]}
{/each}

... the page misbehaves and doesn't immediately update. (Same with setting to undefined.)

And sure enough, when I change that to:

{#each Object.entries(objInState) as [key, value]}
  {value}
  <button on:click={_ => {
    delete objInState[key]
    objInState = objInState
  }}
{/each}

... it works.

But it's so ugly and confusing to read. Is there a way to achieve this behavior without assigning a variable to itself?


Solution

  • There is a pattern of constructing a new object which necessitates an assignment and thus will always trigger reactivity (in Svelte 3/4); this is common for arrays:

    array = array.filter(v => v != valueToDelete)
    

    You can do something similar here, but it is significantly less pretty for objects:

    object = Object.fromEntries(
      Object.entries(object).filter(([k]) => k != key)
    )
    

    (Though, the logic could be extracted to a function.)


    In Svelte 5 delete alone already works with $state.