-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Description
Describe the problem
I stumbled upon this problem on a table component that receives an array of items and an array of available filters as props.
The component manages its own state, meaning actived filters and the list of filtered items were internal component variables.
Now I need to check if all the filtered items meet some criteria from the parent element. To do this, I would make the filtered_items
variable bindable. Currently, the filtered_items
variable was declaras like this:
<script lang="ts">
const {items = $bindable(), filters = []} = $props();
let applied_filters = $state({});//Logic to manage this variable has been omitted
const filter = ()=>{
const active_filters = Object.values(applied_filters).filter(Boolean);
const filtered = items.filter(x => active_filters.every((clause) => clause.evaluate(x)));
return filtered;
}
const filtered_items = $bindable($derived.by(filter));
</script>
If I wanted to make filtered_items
bindable to be able to know which items are currently displayed on the table from the parent component, I would need to use an $effect
, rather than a $derived
:
<script lang="ts">
const {items = $bindable(), filters = [], filtered_items = $bindable()} = $props();
let applied_filters = $state({});//Logic to manage this variable has been omitted
$effect(()=>{
const active_filters = Object.values(applied_filters).filter(Boolean);
const filtered = items.filter(x => active_filters.every((clause) => clause.evaluate(x)));
filtered_items = filtered;
});
</script>
This is philosophically wrong. filtered_items
is still a $derived
but we are using an $effect
to do that just because the compiler will complain about something like this:
<script lang="ts">
const {items = $bindable(), filters = [], filtered_items = $bindable($derived.by(filter))} = $props();
let applied_filters = $state({});//Logic to manage this variable has been omitted
const filter = ()=>{
const active_filters = Object.values(applied_filters).filter(Boolean);
const filtered = items.filter(x => active_filters.every((clause) => clause.evaluate(x)));
return filtered;
}
</script>
Describe the proposed solution
I would like to be able to use $derived
and $derived.by
in props destructuring. Now that deriveds can be writable I don't see why this shouldn't be allowed.
Having to change from a $derived
to an $effect
just because you want the variable to be readable from outside seems wrong.
We may want to differentiate between writable deriveds and readonly ones. For this we can use $bindable($derived())
(writable) VS just $derived()
(readonly, can still be bound, any initial value provided by the parent component will be ignored).
Importance
nice to have