levant pied
levant pied

Reputation: 4501

Svelte avoid superfluous reactive changes

I have a piece of Svelte code that is supposed to:

https://svelte.dev/repl/5d64d5ba6c5e4df6b12cb4c1fb3b716b?version=3.49.0

<script>
    let num
    let msgs = []
    
    const inc = function() {
        num += 1
    }
    
    const load = function() {
        const num_ = 1
        msgs = [...msgs, 'load num ' + num_]
        num = num_
    }
    
    const save = function(num_) {
        msgs = [...msgs, 'save num ' + num_]
    }
    
    $: save(num)
</script>

<button on:click={load}>Load</button>
<button on:click={inc}>Inc</button>

{#each msgs as msg}
    <li>{msg}</li>
{/each}

My problem is that, after loading the page and clicking Load and Inc once each, I get this result:

save num undefined
load num 1
save num 1
save num 2

where I have two superfluous saves:

save num undefined
save num 1

I know I can manually track these with additional variables and what not, but is there a better way to avoid these?

Upvotes: 1

Views: 152

Answers (2)

7nik
7nik

Reputation: 106

The reactive blocks run during the component initialization as well. This is why you get save num undefined.

If you want just rid of this line, check the num value:

$: if (num !== undefined) save(num);

If the num is defined with some tricky value, and in some other cases, you need to use a flag:

let ready = false;
onMount(() => {
  ready = true;
});

function save(num_) {
  if (!ready) return;
  // your code
}

$: save(num);

Also, just calling save at the end of inc and load is a good way to control when the function is called.

Upvotes: 0

brunnerh
brunnerh

Reputation: 185140

If load/save are expensive operations (e.g. server/DB calls), they should be gated by using events or debounced updates (changes schedule an update, rather than executing them directly).

If load/save are just affecting local state, it should not matter that there are superfluous calls. Svelte updates DOM fairly selectively and its change tracking is not very expensive (compared with other mechanisms like dirty checking the whole model or virtual DOM reconciliation).

By using a blanket reactive statement there is no way to differentiate between initialization, load or user initiated mutation which causes those superfluous calls.

In general I would recommend to use reactive statements primarily for simple invariants that do not rely on the number of calls.

Upvotes: 0

Related Questions