sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
77.44k stars 4.03k forks source link

Svelte 5: Can not reassign $derived variable #12001

Closed Lucstay11 closed 3 weeks ago

Lucstay11 commented 3 weeks ago

Describe the bug

Can not reassign $derived variable

Reproduction

let tacheinput= $state(") let title = $derived("Todo App:" +tacheinput)

title = "my new title" // not work

Logs

No response

System Info

not usefull

Severity

blocking all usage of svelte

brunnerh commented 3 weeks ago

That is intended behavior. What real use case do you have for this?

(There are approaches that use $state + $effect, though that is generally discouraged as it can lead to issues.)

MotionlessTrain commented 3 weeks ago

Being able to assign to $derived variables could lead to ambiguous cases:

Would the original object be updated here, when you would be able to assign to prop?

const { obj } = $props()

let prop = $derived(obj.prop)

(Would seem logical behaviour to me, that it would)

But would a be updated here?

let a = $state(2)

let b = $derived(a * 2)

In this case, I would assume not.

The current case is the most non-ambiguous solution, to prevent this entirely

Conduitry commented 3 weeks ago

As mentioned, this is intended. If you want something that automatically updates based on changes to another value, but which also lets you update the value, you can use a pattern like that in #11982.

Lucstay11 commented 3 weeks ago

wtf is that...

In svelte 4 you can reasign reactive variable:

let a = 1 $: b ="the value of a is: "+a b = "a has no more value!" // this work !

In svelte 5 you can not do this:

let a = $state(1) b = $derived("the value of a is: "+a) b = "a has no more value!" // this not work -> error $derived() can not reasign value

I understand using runes to simplify code readability but you destroy responsiveness. You cannot declare a $derived as a const because you prevent yourself from changing the value of a variable which no longer makes sense.

I love svelte for its simplicity but react becomes more logical because it knows how to differentiate reactive from non-reactive variables itself.

brunnerh commented 3 weeks ago

Again, what is your actual use case?

This example in particular can probably be expressed in one derived statement along these lines:

let a = $state(1)
const b = $derived(
  a == null
    ? 'a has no value'
    : `the value of a is ${a}`
);

And as stated, you can use $state and $effect instead of a $derived; you just need to be aware of potential issues like infinite loops from reading and writing the same state.

Lucstay11 commented 2 weeks ago

There is no concrete case, it is just a logical situation. Sometimes we will want to completely change the value of a $derived() . Which was possible in svelte4 and not anymore. I don't understand this change... Just why did you define $derived as an immutable variable? You still don't answer my question...

brunnerh commented 2 weeks ago

Having something that is both computed and writable at the same time is a recipe for bugs. You change something, the dependencies are slightly affected and the computation triggers again, unexpectedly overwriting a manually set value. It's just not a good idea.

If the value is only computed, it does functionally not matter how many times and when the computation happens, as long as it happens at least after any dependency change. The worst outcome is that you may have wasted some CPU cycles.

Lucstay11 commented 2 weeks ago

Okay, I don't know the engineering behind Svelte so if you say that this was removed to maintain better performance I can imagine it. However, this put me off a little because we can do it with other frameworks like React, view...