Skip to content
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

object on right side of = operant in reactive statement is updated, when variable on left side is changed by bind:value, while variable doesn't change #7045

Closed
Mlocik97 opened this issue Dec 23, 2021 · 7 comments
Milestone

Comments

@Mlocik97
Copy link
Contributor

Mlocik97 commented Dec 23, 2021

Describe the bug

<script>
	let bar = {a:"hello"}
	$: foo = bar.a;
	$: console.log(`bar updated ${bar.a}`);
</script>

bar: <input type="text" bind:value={bar.a}/>
<br>
foo: <input type="text" bind:value={foo}/>

change foo (type something to input foo), it will update bar.a, foo is blocked, will not change text in input.

Reproduction

https://svelte.dev/repl/60487dd8d6f941b3bc2e0d72124a2abb?version=3.44.3

Logs

No response

System Info

REPL

Severity

annoyance

@robertadamsonsmith
Copy link

I'm not sure what behaviour it is that you expect. "$; foo = bar.a" means that you expect foo to always be whatever bar.a is, and "bind:value={foo}" means that you expect foo to to be whatever has been entered in the input. It can't be both!

Maybe svelte should raise an error to stop any attempt to bind to a reactive value, instead of allowing it to work (albeit with likely undesired behaviour)

@Mlocik97
Copy link
Contributor Author

Mlocik97 commented Dec 23, 2021

 "$; foo = bar.a" means that you expect foo to always be whatever bar.a is

is not true... this means, value of foo is set to same as value of bar.a, whenever bar.a change... means, foo can be different than bar.a, if foo is changed, because it doesn't change bar.a so reactive statement is not executed so, foo should have value from bind:value. And this works correctly, if not using bind:value,.. see example with setTimeout():

https://svelte.dev/repl/707142058b574f3eb1e674f72551b19f?version=3.44.3

E: and this is correct behaviour, that should work also with bind:value and object properties.

E: Interesting,... robertadamsonsmirth answered totally incorrect answer and got thumb up emoji, even tho, right here is proof, they were incorrect.

@gtm-nayan
Copy link
Contributor

#4933, sounds like the third point there

@TylerRick
Copy link

Yes, this is confusing. It's not clear why you're not able to change foo independently of foo.a and have foo be temporarily "out-of-sync" (see #4933) from $: foo = bar.a. As long as bar.a hasn't changed since foo has changed, it seems like $: foo = bar.a should not re-run.

... depending on your mental model of how you expect reactive statements to work, as discussed in #4933. If you expect $: foo = bar.a to be expression an invariant that must always be kept true by the Svelte run-time, then I guess it's working as expected. But if you expect (as is my expectation after using Svelte for a year or so now) $: foo = bar.a to only re-run if it's dependency (bar.a) changes, then this is a surprising and incorrect behavior.

This behavior was introduced by #2444 in Svelte 3.2.1+, so if you run your first example using 3.2.0 (https://svelte.dev/repl/60487dd8d6f941b3bc2e0d72124a2abb?version=3.2.0), you'll see that it did indeed use to allow you to change the foo input independently, and then only reset foo based on your $: foo = bar.a; if you changed the bar.a input.

@dummdidumm
Copy link
Member

This comes down to $: standing for two things and it's not easy to distinguish:

  • side effects that happen in reaction to something
  • derived state that keeps values in sync

Svelte 5 fixes this by separating these into two distinct runes, $effect and $derived. That way it's much clearer what's going on and such edge cases are avoided entirely.
In this case, you would have a $state variable and either update that through the binding of from an $effect, resulting in the desired behavior.

@dummdidumm dummdidumm added this to the 5.x milestone Nov 15, 2023
@JorensM
Copy link

JorensM commented Mar 20, 2024

Hello, anyone have any ideas how to solve this in Svelte 3? I don't want the right side of a $: to be reactive, it doesn't make sense to me.

@JorensM
Copy link

JorensM commented Mar 20, 2024

Update: I managed to solve this by doing the following:

$: updateFoo(bar);

const updateFoo = (...args: any[]) => {
   foo = bar.a;
}

$: console.log(`bar updated ${bar.a}`);

now bar won't be updated when foo changes and the console.log won't be called.

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

No branches or pull requests

6 participants