Stanislau Listratsenka
Stanislau Listratsenka

Reputation: 680

Does Svelte have the mechanism to listen to only nested properties changes?

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

Answers (3)

Corrl
Corrl

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

Pixievolt No. 1
Pixievolt No. 1

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

Gavin
Gavin

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)

REPL here

Upvotes: 1

Related Questions