I have a component that maintains a selection as an array and a child component that determines its state by seeing if it is included in that array. When I change the array, the child component does not re-render. How do I fix this?
REPL: https://svelte.dev/repl/f2074ef75dee444faaee005b8b7cf9b9
App.svelte
<script>
import Nested from "./Nested.svelte";
let selection = [];
function isSelected(n) {
return selection.indexOf(n) > -1;
}
function click(e) {
const n = e.detail.number;
if (isSelected(n)) {
selection = selection.filter(x => x != n);
} else {
selection = [...selection, n];
}
console.log("Selection is", selection);
}
</script>
{#each [1, 2, 3] as number}
<Nested
{number}
selected={isSelected(number)}
on:click={click} />
{/each}
Nested.svelte
<script>
export let selected, number;
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
function click() {
dispatch("click", {
number
});
}
</script>
<style>
.selected {
color: red;
}
</style>
<div class:selected={selected} on:click={click}>
{number}
</div>
The problem is this
selected={isSelected(number)}
In this expression:
isSelected(number)
Svelte will update for every change to any variable in the expression. That is: either isSelected or number.
In you case, you want to react to a change to selection, and so it doesn't do it.
You can inline the condition, so that the selection variable is directly mentioned in the expression:
selected={selection.indexOf(number) > -1}
Or you can just do that:
selected={selection, isSelected(number)}
The comma syntax x, y is just somewhat obscure JS syntax for an expression which value resolves to the last item (try 'a', 'b', 'c' in your console to see what I mean)... But in this case, it allows to hint Svelte that it should pay attention to the selection variable here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With