Reputation: 331
I have been experimenting with svelte derived stores. If you look at the console log in the following example, after incrementing store 1 and store 2, then hitting reset, the derived store emits 2 updates.
How would you make this atomic or perhaps debounce it? For example, lets say the scenario were that the derived store issued a new network request based on the combined values of store 1 and 2, if they both changed together you wouldn't want to fire 2 network requsts?
https://svelte.dev/repl/a67c9d37aee348d988e8c30f60a139d9?version=3.28.0
EDIT: Actually, just added a 'reactive' console log and this appears to debounce (tick?) the output.
I think I have answered my own question?
Upvotes: 1
Views: 2221
Reputation: 49
Adding onto @TanLiHau's answer, you can also do this without the "global"/outer scope variable timeoutId
.
Svelte's derived
allows to return a callback for cleaning up (https://svelte.dev/docs#derived):
If you return a function from the callback, it will be called when a) the callback runs again, or b) the last subscriber unsubscribes.
This allows you to write it as follows:
const total = derived([counter1, counter2], ([c1,c2], set) => {
const timeoutId = setTimeout(() => {
console.log(c1, c2);
return set(c1+c2);
}, 1000);
return () => clearTimeout(timeoutId)
}, 0);
Upvotes: 3
Reputation: 2334
The derived store's callback 2nd argument is set
, which allows setting the derived value asynchronously.
import { derived } from 'svelte/store';
const delayed = derived(a, ($a, set) => {
setTimeout(() => set($a), 1000);
});
$: console.log($delayed);
$a = 1;
// console '1' 1 second later.
For your case, you could call a debounce function that will eventually call set
:
// implementing debounce yourself
let timeoutId;
const total = derived([counter1, counter2], ([c1,c2], set) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
console.log(c1, c2);
return set(c1+c2);
}, 1000);
}, 0);
Upvotes: 4