I'm sure this is a super easy fix, but I'm having an issue where I setup a writable store, and it's mostly reactive, except when a component changes the data, the reactivity in the App file doesn't fire and vice versa. Here's the code:
App.svelte:
<script>
import { data } from './store.js'
import Component from './Component.svelte'
let localData
data.subscribe((value) => {
localData = value;
});
</script>
<h2>In App.svelte</h2>
<p>Hello {localData.name}!</p>
<input name="name" type="text" bind:value={localData.name}>
<p>
{localData.details.number}
</p>
<h2>In Component.svelte</h2>
<Component />
Component.svelte:
<script>
import { data } from './store.js'
let localData
data.subscribe((value) => {
localData = value;
});
</script>
<input type="number" bind:value={localData.details.number}>
<p>Hello {localData.name}!</p>
<p>{localData.details.number}</p>
store.js:
import { writable } from 'svelte/store'
export let data = writable({
name: 'Bob Smith',
details: {
dob: '1982/03/12',
favoriteFoods: ['apples', 'pears', 'bourbon'],
number: 1
},
})
And, if you want to use it in the Svelte REP: https://svelte.dev/repl/164227336d6c4cc29f7ea0a15e89c584?version=3.44.3
You are subscribing to the data and putting it into a local variable and then bind to that. This means the store does not know that anything changed and updates won't be propagated. Two options:
First option: You get rid of the two way binding and update the store explicitely like this:
<script>
import { data } from './store.js'
import Component from './Component.svelte'
let localData
data.subscribe((value) => {
localData = value;
});
function updateName(evt) {
const newName = evt.target.value;
data.update(value => ({...value, name: newName }));
}
</script>
<h2>In App.svelte</h2>
<p>Hello {localData.name}!</p>
<input name="name" type="text" value={localData.name} on:input={updateName}>
<p>
{localData.details.number}
</p>
<h2>In Component.svelte</h2>
<Component />
This is very explicit but also a bit boilerplate-y. We have Svelte's handy auto subscription feature, so let's use that instead. Second and prefered option:
<script>
import { data } from './store.js'
import Component from './Component.svelte'
</script>
<h2>In App.svelte</h2>
<p>Hello {$data.name}!</p>
<input name="name" type="text" bind:value={$data.name}>
<p>
{$data.details.number}
</p>
<h2>In Component.svelte</h2>
<Component />
Notice how we got rid of all the subscription boilerplate. $data
accesses the current state of the store and since it's a writable store you can also write back to it that way. You can read more about stores in the docs: https://svelte.dev/docs#component-format-script-4-prefix-stores-with-$-to-access-their-values