Skip to content

Stores

wybthon.store

store

Reactive stores for nested state, inspired by SolidJS createStore.

Stores provide fine-grained reactive access to nested objects and lists. Each path through the store is backed by its own Signal, so reading store.user.name only subscribes the current computation to that specific leaf, not to the entire store.

Public surface:

  • create_store: build a store from any initial value.
  • produce: batch mutations through a mutable draft.
  • reconcile: diff external data into a store, preserving object identity for unchanged items.
  • unwrap: read the raw (non-reactive) data behind a store proxy.
  • create_mutable: a directly-writable store proxy (no separate setter).
Example
from wybthon import create_store, produce

store, set_store = create_store({
    "count": 0,
    "user": {"name": "Ada", "age": 30},
    "todos": [
        {"id": 1, "text": "Learn Wybthon", "done": False},
    ],
})

store.count           # 0
store.user.name       # "Ada"
store.todos[0].text   # "Learn Wybthon"

set_store("count", 5)
set_store("user", "name", "Jane")
set_store("count", lambda c: c + 1)
set_store("todos", 0, "done", True)

set_store(produce(lambda s: setattr(s, "count", s.count + 1)))
See Also

Functions:

Name Description
create_store

Create a reactive store from an initial value.

reconcile

Diff external data into a store, keeping identity for unchanged items.

unwrap

Return the raw data behind a store proxy (non-reactive).

create_mutable

Create a directly-writable reactive store proxy.

modify_mutable

Apply a batched modification to a create_mutable proxy.

produce

Create a producer for batch-mutating store state.

create_store

create_store(initial: Any) -> Tuple[Any, _StoreSetter]

Create a reactive store from an initial value.

Parameters:

Name Type Description Default
initial Any

Initial state. Dicts and lists are wrapped in reactive proxies; other values are returned unchanged.

required

Returns:

Type Description
Any

A tuple (store, set_store) where store is a reactive

_StoreSetter

proxy that tracks reads per-path, and set_store is a setter

Tuple[Any, _StoreSetter]

supporting path-based updates and

Tuple[Any, _StoreSetter]

produce batches.

Example
store, set_store = create_store({"count": 0, "user": {"name": "Ada"}})

store.count         # 0
store.user.name     # "Ada"

set_store("count", 5)
set_store("user", "name", "Jane")
set_store("count", lambda c: c + 1)

See the module docstring for the full set of supported calling conventions.

reconcile

reconcile(data: Any, key: Optional[str] = 'id') -> _ReconcileResult

Diff external data into a store, keeping identity for unchanged items.

Matches SolidJS's reconcile. Pass the result to a store setter; instead of replacing the state wholesale, the incoming data is merged: dicts update key by key, and lists of dicts are matched by key so existing item objects are updated in place rather than replaced. Only the leaf signals whose values actually changed notify, and For rows for unchanged items keep their DOM.

Parameters:

Name Type Description Default
data Any

The incoming plain data (dict, list, or scalar).

required
key Optional[str]

Dict key used to match list items. Defaults to "id". Pass None to disable key matching (positional replace).

'id'

Returns:

Type Description
_ReconcileResult

A marker object recognized by the store setter.

Example
set_store("todos", reconcile(fetched_todos))

unwrap

unwrap(value: Any) -> Any

Return the raw data behind a store proxy (non-reactive).

Matches SolidJS's unwrap. Reading the result doesn't subscribe to anything; mutations to it bypass reactivity entirely.

Parameters:

Name Type Description Default
value Any

A store proxy (or any value).

required

Returns:

Type Description
Any

The underlying dict/list for proxies; value unchanged

Any

otherwise.

create_mutable

create_mutable(initial: Any) -> Any

Create a directly-writable reactive store proxy.

Matches SolidJS's createMutable: reads are tracked per path like create_store, and writes go through plain attribute or item assignment at any depth. Nested dicts wrap in writable proxies, and nested lists support append, insert, pop, remove, clear, and index assignment. Each write batches its notifications; use modify_mutable with produce or reconcile to group several changes into one update.

Parameters:

Name Type Description Default
initial Any

Initial dict state.

required

Returns:

Type Description
Any

A mutable reactive proxy.

Example
state = create_mutable({"count": 0, "user": {"name": "Ada"}, "tags": []})
create_effect(lambda: print(state.count, state.user.name))
state.count = 5             # effect re-runs
state.user.name = "Grace"   # nested write, effect re-runs
state.tags.append("new")    # list mutation, tracked

modify_mutable

modify_mutable(state: Any, modifier: Any) -> None

Apply a batched modification to a create_mutable proxy.

Matches SolidJS's modifyMutable. The modifier is either a produce draft function, a reconcile result, or a plain callable receiving a mutable draft (shorthand for produce). All resulting signal notifications flush once, as a single update.

Parameters:

Name Type Description Default
state Any

A proxy created by create_mutable (or any store proxy).

required
modifier Any

A produce(...) / reconcile(...) result, or a callable draft mutator.

required
Example
state = create_mutable({"a": 1, "b": 2})
modify_mutable(state, produce(lambda s: (
    setattr(s, "a", 10),
    setattr(s, "b", 20),
)))
modify_mutable(state, reconcile(fetched_state))

produce

produce(fn: Callable[..., None]) -> _ProduceResult

Create a producer for batch-mutating store state.

fn receives a mutable draft of the store. Mutations are recorded and applied reactively when the producer is passed to a store setter created by create_store.

The draft supports attribute access, item access, and append / pop for lists.

Parameters:

Name Type Description Default
fn Callable[..., None]

A function that mutates the supplied draft. The draft is consumed immediately when applied; don't keep a reference past the call.

required

Returns:

Type Description
_ProduceResult

A marker object recognized by the store setter.

Example
set_store(produce(lambda s: setattr(s, "count", s.count + 1)))

set_store(produce(lambda s: s.todos.append(
    {"text": "New", "done": False}
)))

Public API

Store creation
  • create_store(initial) -> (store, set_store). Create a reactive store from a dict or list.
  • create_mutable(initial) -> proxy. Create a directly-writable store proxy (Solid's createMutable). Attribute and item assignment work at any depth: nested dicts wrap in writable proxies, and nested lists support append, insert, pop, remove, clear, and index assignment.
  • modify_mutable(state, modifier). Apply a batched modification to a mutable proxy (Solid's modifyMutable). The modifier is a produce(...) result, a reconcile(...) result, or a plain callable receiving a draft; all notifications flush as one update.
Store setter

The set_store setter supports several calling conventions:

  • set_store("key", value). Set a top-level key.
  • set_store("key", fn). Functional update (fn receives current value).
  • set_store("a", "b", value). Nested path.
  • set_store("a", 0, "done", True). Path with list index.
  • set_store(produce(fn)). Batch mutations via produce.
  • set_store({"a": 1, "b": 2}). Update multiple top-level keys.
  • set_store(fn). Functional update on the entire store (fn receives raw data).
Produce
  • produce(fn). Create a producer for batch-mutating store state; pass to set_store.
Reconcile and unwrap
  • reconcile(data, key="id"). Create a reconcile marker for set_store: the new data is diffed into the existing state so only changed paths notify. List items are matched by key, preserving proxy identity across updates (important for For).
  • unwrap(value). Return the raw data underneath a store proxy without tracking. Plain values pass through unchanged.
set_store("todos", reconcile(fetched_todos))
raw = unwrap(store.todos)

Type hints are provided for all public functions and classes.