Kevin Renskers
Kevin Renskers

Reputation: 5960

Nested reactive state passed as a property

I have a SvelteKit app using Svelte 5. My app shows a basket, using a BasketLine component to show every product in the basket with its quantity:

<script lang="ts">
  interface Props {
    line: BasketLineWithOffers;
  }

  const { line }: Props = $props();
</script>

<div>
  <h2>{line.product.title}</h2>
  <NumberPicker min={1} bind:value={line.quantity} />
</div>

This is giving a runtime warning in the console:

[svelte] binding_property_non_reactive bind:value={line.quantity} (src/lib/basket/BasketLine.svelte:96:30) is binding to a non-reactive property https://svelte.dev/e/binding_property_non_reactive

Using the number picker (a simple component showing a number input as well as plus and minus button) doesn't change the quantity.

Using const { line = $bindable() }: Props = $props(); doesn't fix it either. So what is the correct way to pass a bindable line property to the BasketLine component in such a way that its properties are also bindable/reactive state? line is just a simple JSON object coming from the server.

Upvotes: 1

Views: 201

Answers (1)

brunnerh
brunnerh

Reputation: 185280

In runes mode, the object passed in needs to be reactive, i.e. $state, otherwise modifications of the properties will not trigger updates. You will get warnings if you modify a property that is not marked $bindable but this has no runtime effect when modifying the property rather than reassigning it.

To get rid of the warnings, the property should be declared $bindable and used with bind:line on the parent.

E.g.

<script>
    import Component from './Component.svelte';

    let line = $state({ quantity: 1 });
</script>

<Component bind:line />
<!-- Component.svelte -->
<script>
  const { line = $bindable() } = $props();
</script>

<input type=number min={1} bind:value={line.quantity} /> <br>

Quantity: {line.quantity}

Playground

If you cannot control how the parent passes the object and you need local reactivity, you probably need to declare a local $state variable from the property (and possibly synchronize it on prop change via an $effect).

Upvotes: 1

Related Questions