Is there a way to control the subscriptions to the store? If not, then maybe that'll be a good addition.
Example:: what works::
<script>
let count = 1
$: alert(JSON.stringify(count))
function handleClick() {
count = 1
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
As expected, this only alerts it once,
But, what doesn't work::
<script>
let count = { check: "false"};
$: alert(JSON.stringify(count))
function handleClick() {
count = { check: "false"};
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
This block, runs everytime even though the underlying object doesn't change. So, is there an abstraction available where we can provide a custom override depending on which svelte decides if it needs to re-run this $ block??
@Bryze: This is probably due to object literals not being strictly equal to each other.
You can get around this for now either by using a more flat structure (like you did in the first example) or by encoding your state object and decoding it in your subscribed handlers.
e.g:
<script>
let count = JSON.stringify({ check: "false"});
$: alert(JSON.parse(count).check)
function handleClick() {
count = JSON.stringify({ check: "false"});
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
Since the state is now encoded in JSON, Svelte will be able to check the string equality and only fire any bound handlers if the content of the JSON string changes.
I'm not sure if the Svelte team would want to implement this as a default behaviour for types that are equal by reference as developers might expect such behaviour (but it could be worth adding this use case to documentation if it is not there already).
@aychtang I understand that implementing such behavior won't be desirable, but what if somehow there is a need to have a $ block which only runs for one store variable.
eg: following is the problem statement
$: if(count>0) {
console.log(x);
}
Now, is there a way to only re-run the block if count changes ( both variables count and x are being updated )
What I am trying to phrase here is:: a way of giving back the control to the developer on how a $ block is re-run
If you need to 'hide' from the compiler which variables are accessed in a reactive block, the recommended idiom for that is to move usages of them into another function and call that.
function log_x() {
console.log(x);
}
$: if (count > 0) log_x();
Svelte only considers variables that are referenced within the $ statement itself.
If you need more complete control, another common idiom is to use a sequence expression:
$: dependency_1, dependency_2, dependency_3, thing_to_run();
@Conduitry I can't easily find an example of this in the tutorial / API docs - is it something you would want to add?
EDIT: Also how's this sequence expression work 馃, is it a feature from your compiler? I also can't find such an example in the docs.
I think this is the sort of thing that would belong in a guide or cookbook section - which was at least started some months ago by @pngwn and I think he still intends to get it into a publishable state eventually.
The sequence expression is just using the comma operator.
@Conduitry wow I did not know how that operator really worked until just now and I've been using JS for something like 10 years 馃う鈥嶁檪
@Conduitry thanks a lot for the insight, makes sense now
Yeah, this is exactly the sort of thing the cookbook would cover.
Apologies in that regard, I hoped to be much closer to PRing the cookbook than I currently am but the past month has been particularly challenging. Hopefully things will be less frenetic in the new year and I can make better progress on this.
fwiw, I made an REPL that shows some ways to control reactive statements for these kind of scenarios. For instance, watching sub properties of reactive variables.
It also shows the main scenario discussed here--referencing reactive variables in a reactive statement that shouldn't cause the statement to run when they change.
https://svelte.dev/repl/b30e1e2885aa4d24a4ff98f993711d71?version=3.16.7.7
Most helpful comment
If you need to 'hide' from the compiler which variables are accessed in a reactive block, the recommended idiom for that is to move usages of them into another function and call that.
Svelte only considers variables that are referenced within the
$statement itself.If you need more complete control, another common idiom is to use a sequence expression: