I have three files:
App.svelte
:
<script>
import Component from "./Component.svelte"
import { items } from "./store.js"
$items.set("a", { name: "John", index: "a" })
$items.set("b", { name: "Jack", index: "b" })
</script>
<h1>DIV each:</h1>
{#if $items && $items.size > 0}
{#each $items.values() as item}
<div>Name: {item.name}</div>
{/each}
{/if}
<h1>Component each:</h1>
{#if $items && $items.size > 0}
{#each $items.values() as item}
<div><Component index={item.index} /></div>
{/each}
{/if}
Component.svelte
:
<script>
import { items } from "./store.js"
let { index = null } = $props()
let data = $state($items.get(index))
</script>
<div><input bind:value={data.name} /></div>
store.js
:
import { writable } from "svelte/store";
import { SvelteMap } from "svelte/reactivity";
export let items = writable(new SvelteMap([]))
I wonder how to remain reactivity in SvelteMap items
. When input value is changed, it should update in SvelteMap (as it is binded). I don't know how to work with this kind of reactivity.
If you modify items in the map instead of fully replacing them, the items themselves have to be stateful.
E.g.
const john = $state({ name: "John", index: "a" });
$items.set("a", john);
const jack = $state({ name: "Jack", index: "b" });
$items.set("b", jack);
Wrapping objects and arrays in $state
creates a Proxy
which triggers signals on property change that cause reactive updates.
Doing the above will cause state ownership warnings though, since the state is created in one component and modified in another without binding.
You could circumvent this by not using global state to access the items but by using a bound property or by putting all state creation and modification in the same place and only exposing that via specific functions.