-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Closed
Labels
Description
Describe the problem
This is a bit of a rehashing of #9250 prompted by seeing more of this discussion coming up in the Discord
TL:DR there's still animosity around people's preferences regarding the design choice for $derived
accepting an expression instead of a callback function, and how it becomes slightly less ideal for the scenarios where you want to encapsulate more complex logic that wraps onto multiple lines.
Describe the proposed solution
Introduce a $derived.with
rune, which accepts a callback for determining the derived value instead of an expression.
e.g.
const total = $derived.with(() => {
const discountAmount = cartTotal * promoDiscount;
const taxedAmount = (cartTotal - discountAmount) * taxRate;
return cartTotal - discountAmount + taxedAmount;
});
Alternatives considered
- Keep using IIFE's or defining the logic in functions outside of $derived, given it's really not that big of a deal
- A separate
$computed
rune instead of not being nested under$derived
- Alternative method names:
call
,compute
,using
,from
Importance
nice to have
aradalvand, MrWaip, maxkostin, leon and ivan-liadniou-epam
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
kyle-n commentedon Dec 20, 2023
As the person who sparked the Discord discussion with my blog post, I'd like to second this proposal.
Having the option to use a callback to
$derived.with()
or$computed()
means we avoid verbose alternatives like:I appreciate Svelte's focus on writing less code and hope it will apply here too.
aradalvand commentedon Dec 25, 2023
Seconded, though I prefer the overload approach, adding an extra overload that accepts a function:
While preserving the current signature as the other overload:
But if overloads aren't feasible,
$derived.with
is fine as well, either way, this should be added IMO.Not-Jayden commentedon Dec 26, 2023
I worry overloading
$derived
to behave differently depending on whether it receives a function would probably cause too much confusion.For example in this case:
The way
$derived()
works now it's easy to understand you're just going to get the reactive result of the expression passed into it. If it were to be overloaded, it's not immediately obvious to me whethertotal
would be a function, or if it should get called and return the value reactively.Also need to consider that it would be a breaking change to alter how
$derived
behaves directly, even though 5 isn't a GA release yet.kyle-n commentedon Dec 26, 2023
I think overloading
$derived
to accept an expression or a callback would be ideal. Checking if something is a function is pretty negligible performance-wise. Allowing callbacks also provides the shortest, most developer-friendly syntax.Svelte is all about writing less code. Let’s not have a separate function or an IIFE or
$derived.with
if we can skip it (though it’s an acceptable second option in my book).TGlide commentedon Dec 26, 2023
Overloading is not the best idea. What if I want to return a function from derived? Now I need to return a function from within a function.
aradalvand commentedon Dec 27, 2023
Okay, the reasons against it being an overload sound compelling.
$derived.with
seems to be the ideal approach then.D-Marc1 commentedon Dec 29, 2023
Personally, I still think my original proposal of
$derived()
only allowing a function passed in is the most ideal. It's very confusing for someone coming into Svelte for the first time seeing this:const countDoubled = $derived(count * 2)
, as this is not allowed in vanilla JS.The Svelte 5 literature constantly states that the reason for their changes are to reduce the learning curve, so why go against that when it comes to
$derived()
? I still don't get why the Svelte core team thinks that this non-standard syntax is worth it all to save four characters for a single line:const countDoubled = $derived(() => count * 2)
. I don't see what's so bad about this. Not to mention, the current$derived()
syntax adds four extra characters for multiline, as you need to wrap it in an IIFEE, so it ends up being a wash, anyway.Current
$derived()
multilineFunction argument proposal for
$derived()
multilineMrWaip commentedon Jan 5, 2024
This is definitely a necessary feature.
We have a ton of derived stores that compute complex conditions. Without that proposal we will get a problems while migration
TGlide commentedon Jan 5, 2024
Why is it necessary? It's just a syntax change, you can do what's proposed with a different syntax (IIFEs).
kyle-n commentedon Jan 5, 2024
It can be done with IIFEs, but I’ll restate my post from earlier in this thread and say IIFEs are an awkward, verbose way to code. They go against the whole point of Svelte, to write less code.
TGlide commentedon Jan 8, 2024
I'm not against the change, but saying it is necessary is a stretch. That's all I'm getting at 🙂
pothos-dev commentedon Jan 15, 2024
I think allowing both callback and expression syntax would be best.
In my own experience, derived signals that produce functions are very rare, so I think it's acceptable to force developers to add another indirection for this rare case:
when the compiler sees a function as the expression within
$derived
, it evaluates it when any states directly inside this function change. Any additional functions that are nested within the outer function would just be treated as normal closures.There are many different signal implementations currently in the wild, so far every one that I have seen uses the callback syntax for derived signals. In not allowing this, Svelte would break with the majority of the web ecosystem, which also makes it more confusing for developers coming from other frameworks. There has to be a strong reason to that, and I don't think we have one here.
enyo commentedon Jan 16, 2024
This is definitely allowed in vanilla JS. Nothing wrong here. You evaluate an expression and pass it to
$derived
, which turns it into a reactive variable.That you don't have the overhead of thinking "how does the reactive variable get updated then" (like in react or vue) is a good thing and the power of having a preprocessor like svelte does.
17 remaining items