Open brunnerh opened 8 months ago
Could you give more information why you need this / examples where this would be useful?
One example was given in #9944, where people tried to reproduce the required behavior with both $effect
and $derived
which resulted either in convoluted/buggy $effect
code or the wrong behavior because $derived
cannot change state like props. I noted in a comment how easy this would be, using the proposed hook.
I have usually run into this when properties have dependencies amongst themselves, often related to validation or coercing ranges via a minimum/maximum.
Or instead of a range, a certain format has to be ensured, so if a value is set on the component from the outside, the UI has to be updated, but on user interaction that should not be the case, as it would interfere with typing. Even if you allow the interference, if you try to do this via reactivity, having an underlying and a formatted value, you run into circular dependencies or, in the case of Svelte 5, infinite effect loops. There are some ways around this, but they are unintuitive and complicated.
In v5, today, here a missing link between bind:prop in parent component and same prop in child component. why?
1) child prop (which is bound in parent) can not have a default value 2) you can not use $derived to change bounded prop value 3) it seems possible to use $effect for this - but it is hard (specially with arrays!!!) and can easily cause problems with endless updates.
edit: I would like to explicitly point out the problems with arrays - perhaps there is a good solution specifically for arrays?
And after using $effect, I fully understand that $effect is not a replacement for $:
It is different.
I tried to write about my experience with $effect, but it was closed. https://github.com/sveltejs/svelte/issues/9944 But believe me - this problem will keep you busy with v5, v6, v7 etc. until a solution is found.
onPropChange() is something like afterUpdate - right? But will trigger only, after some prop changed - right? It should not trigger, if YOU change bounded prop inside child component
Solutions from other frameworks: 1) Vue is able to prevent loops - I tested this: https://github.com/sveltejs/svelte/issues/9944#issuecomment-1863423090
2) It seems that Preact have value.peek() to prevent this manually... Is this like untrack? I'm not sure... https://github.com/preactjs/signals#signalpeek
Hey maybe I’m a bit confused here but when bounding props from parent to child isn’t your default value going to be defined in the parent since that’s the flow of the variable? Parent -> child. If you want a default value in child assign that in parent since it’s being passed in?
bind:value is a two-way binding parent and children can change it
For my own interest, I had a go at implementing the example use case with $effect():
<script>
let { values = $bindable(), disabled = $bindable(), maxLength = $bindable() } = $props();
$effect(() => {
if (!values.length) return;
if (disabled) values = [];
if (values.length > maxLength) values = values.slice(0, maxLength);
});
</script>
End result is ok, but debugging infinite loops isn't a great dev experience 😅. untrack
isn't very useful here because you want to listen to all prop changes; the trick is to use conditionals to stop assignment (and thus the loop) once the desired result has been met.
Describe the problem
It was already a pain to enforce consistent internal component state in v4, it's now even harder with v5 because
$effect
will cause infinite loop issues.$derived
is not going to solve this, it serves a different function entirely.Describe the proposed solution
Add a hook that runs on external changes to the props, the callback inside will not be an effect so any changes to or normalization of internal state or props should not cause the handler to re-run. E.g.
The event object could be supplied with the name of the property that was changed, and maybe even old and new values.
Importance
would make my life easier