Fred Hors
Fred Hors

Reputation: 4156

Why is this object not updating?

Reproduction: https://svelte.dev/playground/4424d522f50847f0b872a094b7b2198b?version=5.18.0

I cannot understand why this error:

[svelte] binding_property_non_reactive
`bind:value={content.one}` (Form.svelte:5:19) is binding to a non-reactive property
https://svelte.dev/e/binding_property_non_reactive

Code:

App.svelte:

<script>
    import Form from "./Form.svelte";

    let changed = $state(false);
    
    let content = $derived({one: `hello ${changed}`, two: changed });
</script>

<Form bind:content={() => content, (v) => content = v} />

Form.svelte:

<script>
    let { content = $bindable() } = $props();
</script>

<input type="text" bind:value={content.one} />

Upvotes: 0

Views: 87

Answers (1)

Jorge Linares
Jorge Linares

Reputation: 548

You cannot bind to a derived state, if you want your content to both bindable and reactive to change then you can declare it with a $state rune and use an $effect to update it whenever change updates like this:

<script>
    import Form from "./Form.svelte";

    let changed = $state(false);
    let content = $state({one: `hello ${changed}`, two: changed });
    $effect(() => {
        content = {one: `hello ${changed}`, two: changed }
    });
    
</script>

changed: {changed} <br>
content: {JSON.stringify(content)} <br> <br>

<!-- This does not work! -->
<!-- <Form bind:content /> -->

<Form bind:content={() => content, (v) => content = v} />

<br><br>

<button type="button" onclick={() => changed = !changed}>
    change from App
</button>

This will give you a warning that State referenced in its own scope will never update but it should still work, if you want to get rid of the warning then declare the content using a closure like this:

let content = $state({one: `hello ${(() => {return changed})()}`, two: () => {return changed} });

Here's your REPL working with this fix

Upvotes: 1

Related Questions