Replies: 2 comments 5 replies
-
You don't need effects for this. The proxy can just be a plain object that directly interacts with the prop. <script>
let { value = $bindable() } = $props();
const internalValue = {
get year() { return value.getFullYear(); },
set year(v) { modify(d => d.setFullYear(v)); },
// Note that month is 0-based
get month() { return value.getMonth() + 1; },
set month(v) { modify(d => d.setMonth(v - 1)); },
get date() { return value.getDate(); },
set date(v) { modify(d => d.setDate(v)); },
};
function modify(callback) {
const newDate = new Date(value);
callback(newDate);
value = newDate;
}
</script> Internally fine-grained signalsThe property accessors would trigger signals on any change to the date. This should not really matter in most cases, but if you want to avoid this, you can introduce <script>
let { value = $bindable() } = $props();
const year = $derived(value.getFullYear());
const month = $derived(value.getMonth() + 1);
const date = $derived(value.getDate());
const internalValue = {
get year() { return year; },
set year(v) { modify(d => d.setFullYear(v)); },
get month() { return month; },
set month(v) { modify(d => d.setMonth(v - 1)); },
get date() { return date; },
set date(v) { modify(d => d.setDate(v)); },
};
function modify(callback) {
const newDate = new Date(value);
callback(newDate);
value = newDate;
}
$effect(() => {
// no longer fires on changes to year / date.
console.log('Month changed', internalValue.month);
});
</script> |
Beta Was this translation helpful? Give feedback.
5 replies
-
You can do something like this REPL |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Hello folks!
Sometimes, we need a component to accept one kind of data structure but keep another, synchronized one internally, maintaining a two-way binding between both.
How can we proxy the prop, so that it can be bound externally, but be bidirectionally transformed to a different type inside.
We could do this with the following pattern successfully: Perfectly functional, non-runes REPL here
However, if we substitute it with the
$effect
equivalent that can run more than once atick()
, we get an infinite loop.Runes repl (not working) REPL HERE
I cannot seem to find any way to solve this problem. Are we in need of a new rune?
Hooking into the
$state
or$derived
getters and setters and add a transformation/proxy Fns would make this seemingly common use case much easier. Any slightly modular form / simple CRUD app project has surely found this.Failed attempts:
Using
$derived
and$effect
: (at least as of[email protected]
) weCannot assign to derived statesvelte(constant_assignment)
. REPL.Using a custom
get value()
set value()
object. No fine grained reactivity source. If the$bindable()
value is set to this custom object, it does not get updated. Simply doesn't work.Using the non(yet)existant
$effect.tick
would fix this Svelte 5: Introduce $effect.tick #9986. However, wouldn't this be an antipattern?Beta Was this translation helpful? Give feedback.
All reactions