Skip to content

Improve clarify of documentation around reactivity / $: operator when using function calls #4305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rlaferla opened this issue Jan 23, 2020 · 10 comments

Comments

@rlaferla
Copy link

rlaferla commented Jan 23, 2020

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.

@rlaferla rlaferla changed the title Reactivity of functions vs. variables. Inconsistent reactivity of functions vs. variables. Jan 23, 2020
@vipero07
Copy link

vipero07 commented Jan 23, 2020

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;
}

@rlaferla
Copy link
Author

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?

@vipero07
Copy link

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.

@rlaferla
Copy link
Author

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.

@antony antony added docs and removed question labels Jan 29, 2020
@antony antony changed the title Inconsistent reactivity of functions vs. variables. Improve clarify of documentation around reactivity / $: operator when using function calls Jan 29, 2020
@pngwn
Copy link
Member

pngwn commented Feb 1, 2020

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.

@jchidley
Copy link

jchidley commented Apr 8, 2022

I have recently been tinkering with Svelte and this issue, function calls being triggered once only, has been really difficult to grasp. I have only now just understood this because I have read the following information:

Advanced Svelte: Reactivity, lifecycle, accessibility
add example for reactive declaration with a function? #4785
Explicit dependencies for reactive statements + Syntax proposal or Docs update #5615

In my case, I have been looking at closures and how I might use this to protect private date. Obviously, by design, Svelte will not see private data. Hence the need for an external flag to trigger reactivity.

In my example, below, clearly I could have programmed things differently (i.e. sum doesn't need to be a private function or could be reworked as a pure function).

<script>
	let nums = numberAdder();
	let numUpdate = 0;

	function numberAdder() {
		let n = [1];
		return {
			add: function () {
				n = [...n, n.length + 1];
				numUpdate++;
			},
			joinedUp: function () {
				let joined = n.join(" + ");
				return joined;
			},
			sum: function () {
				let summed = n.reduce((acc, cur) => acc + cur, 0);
				return summed;
			},
		};	
	}
</script>

<main>
	<button on:click={nums.add}>numberAdder</button>
	<p>{nums.joinedUp(numUpdate)} = {nums.sum(numUpdate	)}</p>
</main>

@dummdidumm
Copy link
Member

https://svelte.dev/docs#component-format-script-3-$-marks-a-statement-as-reactive has information on that for a while now, I think that this line makes it clear: "Only values which directly appear within the $: block will become dependencies of the reactive statement. For example, in the code below total will only update when x changes, but not y"

I'm inclined to therefore close this issue, leaving it open for a few more weeks for others to chime in.

@dummdidumm dummdidumm reopened this Apr 8, 2022
@jchidley
Copy link

jchidley commented Apr 8, 2022

This issue has been open for over 2 years and I have been following the Tutorial recently. It wasn't obvious how to deal with Svelte's particular take on reactivity. I have been messing around with it (reactivity) and thinking about it for several days. How many other newbies will be prepared to do this?

The way that Svelte deals with reactivity is fundamental to its design: it still isn't clear to newcomers, like me, how it works.

@alexamy
Copy link

alexamy commented Apr 19, 2023

Looks like api chapter $: marks a statement as reactive describes all the cases.

@dummdidumm
Copy link
Member

Yes, thank you for reminding me to close this 👍 It now also has code examples so it should be sufficiently clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants