Search code examples
sveltesvelte-3

Strange behavior with binding from store


I have some data points, which should be presented in a card grid. Whenever I hover over one of the cards, I update a value in a svelte store.

This value should be used elsewhere (it's the id of the hovered data point).

The issue I have: while the update of the value in the store seems to be working, I cannot access the data from the store in more than one place.

Here is a working REPL with the observed behavior: https://svelte.dev/repl/b37e7ab93f6743f2bea8d193a2fa6e25?version=3.55.1

Just hover over the gray areas (data points). Every data point has it's own id (shown in the name). Every data point also has an orange area, where there should be written the id of the currently hovered data point, but only the orange area of the last data point is updated

<!-- App.svelte -->
<script>
    import Datapoint from './Datapoint.svelte';
    import { keyStore } from "./keys.store";

    let keys = keyStore();

    let activeId = null
    $: {
        activeId = $keys.activeDatapointId;
    }
    const datapoints = JSON.parse('[{"id":2,"name":"Data Point 2"},{"id":37,"name":"Data Point 37"},{"id":36,"name":"Data Point 36"}]');
</script>
<hr>
hovered id: <span>{activeId}</span>
<hr>
{#each datapoints as datapoint, index}
    <Datapoint {datapoint} />
{/each}
<!-- Datapoint.svelter -->
<script>
    import { keyStore } from "./keys.store";

    export let datapoint;
    let id = datapoint.id
    let activeId = null

    let keys = keyStore();

    $: {
        activeId = $keys.activeDatapointId;
    }


    function enter(e) {
        //id = datapoint.id
        keys.setKey('activeDatapointId', id)
    }

    function leave(e) {
        keys.setKey('activeDatapointId', null)
    }
</script>


<div on:mouseenter={enter} on:mouseleave={leave}>
    {datapoint.name}<br>
    hovered id: <span style="background: orange">{activeId}</span>
    <hr>
</div>
// keys.store.js
import { writable } from 'svelte/store';

let status = {}
let subscribe, set;

function setKey(key, value) {
    status = { ...status, [key]: value }
    set(status);
}

export function keyStore() {
    ({ subscribe, set } = writable({}));


    return {
        subscribe,
        setKey,
        clear: () => set([])
    };
}

Solution

  • The keyStore() creates a new store, so for every datapoint a new store is created and the set variable is updated.

    Calling setKey only updates the last created store.

    The fix would be to create the store once and use that instance in all the components