Streetlamp
Streetlamp

Reputation: 1556

How do I re-render a component on variable change that determines state using a function?

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>

Upvotes: 4

Views: 1966

Answers (1)

rixo
rixo

Reputation: 25001

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.

Upvotes: 1

Related Questions