Svelte is inconsistent when it comes to reactivity for variables and functions. As a relative newcomer to Svelte, this has been my #1 struggle. I don't think I'm alone.
PROBLEM: When you refer to a variable, it's reactive. But when you refer to a function, it's not. It's only called once.
It has been surmised in the support channel, that this could be a design issue that was made due to performance issues. If that is the case, is there not a way (in a future version) to mark a function as reactive vs. non-reactive (called once.) Or is there a different approach to this using the current version? If so, this needs to be in the tutorial.
Example:
https://svelte.dev/repl/7f0bf62d89c34b43b4ad5d0c21f0a5ab?version=3.17.2
Also, I can get it to work in this (with a caveat):
https://svelte.dev/repl/faf860418fe645abb75e6abd1eb89b96?version=3.17.2
The caveat being that if you change:
$: checkTrue = () => {
console.log("checkTrue()");
return variable;
}
to
$: checkTrue = () => {
console.log("checkTrue()");
return isTrue();
}
it no longer works.
Inside the reactive statement you need to reference the variable that the function is dependent on. That's why there is possible performance issues with your example. E.G. $: callfunc = isTrue() && variable; fixes your issue. As would $: callfunc = isTrue(variable);. Alternatively per the tutorial:
$: {
variable;
isTrue();
}
Not having that variable inside the reactive declaration would be similar to using a react hook useCallback or useEffect without the dependency array if the function was always run.
I don't think this is an inconsistency, though I do believe it should be made more clear or explicit in the documentation.
It is probably possible for the compiler to figure out the dependencies, but this would require it reading into each function and with one level of depth it isn't bad but the deeper the function rabbit hole goes, the worse it is.
This is also why your second example works with variable inside the reactive declaration, and not when it calls another function.
A more idiomatic approach though, the function you are calling (isTrue) should itself accept the dependencies that it relies on making the function an idempotent function. This would also fix the issue.
let variable = true;
$: callfunc = isTrue(variable);
function isTrue(test) {
console.log("isTrue()");
return test === true;
}
Thanks, I now understand this and I like your idiomatic approach. However, I don't see this in the tutorial. Can we mark this as "docs" instead of "question" even though it's a bit of both, the result should be an update to the tutorial?
Forgot to link, the api docs do mention it only updates when the values that are depended on update. However, it still should probably be made more explicit that the dependencies of dependencies aren't accounted for.
Thanks. I'm still a newcomer to Svelte. I think the tutorial is where fundamental concepts should be explained wheres the reference docs should be for details. In particular, I think there needs to be some visual diagrams and conceptual documentation about when and how reactivity gets evaluated.
The behaviour in the issue is by design but explaining how reactivity works and different approaches are definitely on the cards. I actually have a document doing pretty much that, though it needs some work. Probably something for the cookbook/guides section.
Most helpful comment
The behaviour in the issue is by design but explaining how reactivity works and different approaches are definitely on the cards. I actually have a document doing pretty much that, though it needs some work. Probably something for the cookbook/guides section.