Pascal Schmidt
Pascal Schmidt

Reputation: 243

Use reactive Variables Between Components in Svelte

I have a question regarding using reactive variables from component3 in my example in component 2. I have two checkboxes in component2 and I am having a reactive array that I want to use in component 2 but it does not quite work the way I want it to work. The repl can be found here: https://svelte.dev/repl/b8109591f22541949309be8404336afa?version=3.49.0

This is the main app

<script>
    import Component2 from './Component2.svelte';
    import Component3 from './Component3.svelte';
</script>


<Component3/>
<Component2/>

Component 2:

<script>
    import a2 from './Component3.svelte';
</script>

{#if a2[0]}
<p>
    Hi
</p>
{:else}
<p>
    Not Hi
</p>
{/if}

Component 3

<script>
 let initial_categories = [
        {name: 'SPINS', checked: true}, 
        {name: 'TRAIN', checked: true}
    ]
 let vec_names = [
        'SPINS', 'TRAIN'
    ]
 
    export let a2 = [];
    $: {
     a2 = [];
    for(let i = 0; i < initial_categories.length; i++) {
        let stringify = JSON.stringify(initial_categories[i]);
        stringify = JSON.parse(stringify)["checked"];
      a2 = a2.concat(stringify);
    }
    }
</script>

{#each initial_categories as { name, checked }}
    <label class="cats">
            <input type=checkbox bind:group={vec_names} bind:checked={checked} name="Category" value={name}>
            {name}
    </label>
{/each}

{a2}

Upvotes: 4

Views: 4126

Answers (1)

brunnerh
brunnerh

Reputation: 184376

This does not work:

<script>
    import a2 from './Component3.svelte';
</script>

a2 is simply the constructor of Component3 with a bad name.

You can only export variables that are not bound to component instances from the context="module" script, and those variables will not be reactive, so you need to use stores to preserve reactivity across components.

So something like this in #3:

<script context="module">
    import { writable } from 'svelte/store';
    export let a2 = writable([]);
</script>
<script>
    // ...
    $a2 = [];
    for(let i = 0; i < initial_categories.length; i++) {
        // ...
        $a2 = $a2.concat(stringify);
    }
</script>

And the import will be named instead of the default in #2:

<script>
    import { a2 } from './Component3.svelte';
</script>

{#if $a2[0]}
  <p>Hi</p>
{:else}
  <p>Not Hi</p>
{/if}

REPL


I would recommend defining a shared state higher in the hierarchy and passing it down to the components instead of doing the above. This can be done via props or via a context. With props the store does not need to used as long as the props are using bind: on the components that modify state.

E.g. in the main component:

<script>
    import Component2 from './Component2.svelte';
    import Component3 from './Component3.svelte';
    
    let state = [];
</script>


<Component3 bind:state />
<Component2 {state} />

Then just add export let state to the other two.

REPL

Upvotes: 4

Related Questions