Reputation: 680
I need to do some logic on nested property change. I only found that thing to do that
$: c, console.log('updated');
This approach was suggested by official svelte
developer from this Twitter thread.
But svelte stores
do not work properly with that. For instance I have following code:
<script>
import { writable } from 'svelte/store';
const s = writable({ x: 1, y: 2 });
$: $s && console.log('store updated');
$: $s.x && console.log('store x updated');
</script>
<button on:click={() => $s.y++}>
Update y
</button>
The $: $s.x
part will be triggered on change of $s.y
. How to avoid that??
REPL to play around.
P.S. VueJS
has the feature @Watch('s.x')
.
Upvotes: 2
Views: 1333
Reputation: 7699
You could work around that with the help of a reactive variable REPL
<script>
import { writable } from 'svelte/store';
const s = writable({ x: 1, y: 2 });
$: $s && console.log('store updated');
$: xRef = $s.x
$: xRef && console.log('store x updated');
</script>
<button on:click={() => $s.y++}>
Update y
</button>
Since the dependency xRef
is now a primitive value that hasn't changed, the reactive log won't be triggered
Upvotes: 4
Reputation: 815
In addition to the options presented in other comments, there are also npm packages that can create a store linked to the property of an object in another store. I make one such package, svelte-writable-derived
.
import { propertyStore } from "svelte-writable-derived";
let xStore = propertyStore(s, "x");
let deepStore = propertyStore(s, ["deeply", "nested", "property"]);
If you prefer specifying a nested property by string instead of array, someone else made a svelte-keyed
package that will do what you want.
Svelte by itself provides no such functionality as part of its philosophy to ship only as much code to end users as is needed, and no more. Sure, svelte-writable-derived
is less than 1KB, but that's hundreds of bytes that developers who don't need this feature don't have to ship.
Upvotes: 0
Reputation: 2365
You can subscribe to the store per usual, but only do your logic if the property you're interested in changes like so:
// this is the only bit relevant to this component
let thingWeAreInterestedIn;
// subscribe to changes in the store
const unsubscribe = s.subscribe(val => {
// but if there's no change to the property we're interested in. Do nothing
if(val.y === thingWeAreInterestedIn) return;
// else update it!
thingWeAreInterestedIn = val.y
})
// this now only fires when $s.y is changed
$: console.log('y updated', thingWeAreInterestedIn)
Upvotes: 1