inputexportsveltebindprop

Data prop responsiveness issue when input bind:value in Svelt


When export let data is an object, there is a data prop reactivity problem when using input bind:value.

For example, in the following case

<script>
export let data = {name:"jack", age:31};
$: man = data;
</script>
<input type='text' bind:value={man.name} >
<h1>{data.name}</h1>
<h1>{man.name}</h1>

//input typing jhon
//data.name => jhon
//man.name => jhon

When the bare value of the input changes, the value of the data also changes at the same time. I think it's because of shallow copying.

So, in the case below where deep copy is performed,

<script>
export let data = {name:"jack", age:31};
$: man = structuredClone(data);
</script>
<input type='text' bind:value={man.name} >
<h1>{data.name}</h1>
<h1>{man.name}</h1>

//input typing impossible

Input values ​​cannot be changed.

Ultimately, what I want is for only the value of man to change depending on the input value. (So ​​that the data value does not change)

What am I misunderstanding?

Thank you for reading my post.

<script>
let data = {name:"jack", age:31};
$: man = data;
</script>
<input type='text' bind:value={man.name} >
<h1>{data.name}</h1>
<h1>{man.name}</h1>

//input typing jhon
//data.name => jack
//man.name => jhon

In the case of let data, it does what I want, but I have to use export let data. There is also a way to use $page.data, but more than anything, I want to understand how the above behavior occurs. I would appreciate it if someone could explain.


Solution

  • The reactive statement($:...) keeps overwriting variable man whenever man.name is updated fby bind:value...

    //[code-01]
    export let data = {name:"jack", age:31};
    $: man = Object.assign({},data);
    

    When typing input field, man.name is updated, which triggers variable man to be reset by the reactive statement($:...).

    To avoid it, variable man should be removed from the reactive statement([code-01]).

    <script>
    export let data = {name:"jack", age:31};
    // (1)
    let man 
    // (2)
    const clone = (src) => man = structuredClone(src)
    // (3)
    $: clone(data)
    </script>
    
    <input type='text' bind:value={man.name} >
    <h1>data value: {data.name}</h1>
    <h1>man value: {man.name}</h1>
    
    1. declare variable man
    2. declare function to clone the data
    3. variable data is exposed to be monitored

    man.name is preserved whenever bind:value... changes the text.

    code

    ReactiveInput.svelte

    <script>
    export let data = {name:"jack", age:31};
    let man
    const clone = (src) => man = structuredClone(src)
        
    $: clone(data)
    </script>
    <input type='text' bind:value={man.name} >
    <h1>data value: {data.name}</h1>
    <h1>man value: {man.name}</h1>
    

    App.svelte

    <script>
    import ReactiveInput from "./ReactiveInput.svelte"  
    const jack = {name: 'jack', age: 31};
    const tom = {name: 'Tom', age: 24};
    const mark = {name: 'Mark', age: 43};
    const persons = [jack, tom, mark]
    let idx = 0;
        
    const changePerson = () => {
        idx = (idx + 1) % persons.length 
    }
    </script>
    
    <ReactiveInput data={persons[idx]}></ReactiveInput>
    <button on:click={changePerson}>change</button>