fromState

Signature
fromState<T>(state: Atom<T> | Selector<T>, store?: Store): FromStateAtom<T> | FromStateValue<T>

valdres-svelte Reactive read/write box for an atom (read-only for selectors)

Bridges a valdres atom or selector into a Svelte 5 reactive box. Reading .current inside an effect — a template expression, $derived, $effect — subscribes to the state and re-runs that effect when it changes. For an atom the box is writable, so bind:value and count.current++ just work; for a selector (or any read-only state) .current is read-only.

Usage

<script lang="ts">
    import { atom } from "valdres"
    import { fromState } from "valdres-svelte"

    const countAtom = atom(0)
    const count = fromState(countAtom)
</script>

<p>Count: {count.current}</p>

<button onclick={() => count.current++}>Increment</button>
<button onclick={() => count.update(c => c + 1)}>Increment (updater)</button>
<button onclick={() => count.reset()}>Reset</button>

<!-- two-way binding writes straight back to the atom -->
<input type="number" bind:value={count.current} />

The second store argument defaults to the store from setValdresContext / scope, resolved via getValdresContext. Because context is only available during component initialization, pass an explicit store to use the box in plain .svelte.ts module state or during SSR.

Returns

For an atom (FromStateAtom<T>):

MemberTypeDescription
currentTTracked read and write (box.current = v, box.current++, bind:value)
update(updater: (current: T) => T) => voidRead-modify-write, mirroring svelte/store's Writable.update
reset() => voidReset the atom to its default value

For a selector (FromStateValue<T>): a read-only current. Async selectors surface as current: T | Promise<T> — see the async note below.

Async selectors

Core erases asyncness, so fromState(asyncSelector).current is typed T | Promise<T>. Consume it with Svelte's {#await} block, or reach for resourceState when you want loading / error flags:

<script lang="ts">
    import { fromState } from "valdres-svelte"
    import { userSelector } from "$lib/state"

    const user = fromState(userSelector)
</script>

{#await user.current then u}
    <p>Hello {u.name}</p>
{/await}

Lazy bootstrap
The box is built on Svelte's createSubscriber (the primitive behind MediaQuery), so the underlying subscription is lazy: it starts on the first effect that reads .current. A valdres onMount-driven atom — the @valdres/browser-* packages — therefore bootstraps only once .current is read in the template or an effect. If a component reads the value solely from an event handler, start the subscription with a throwaway effect: $effect(() => void box.current).

See also