Skip to content

reactivity

wybthon.reactivity

Signal-based reactive primitives and async Resource helper.

Computation

Reactive computation that tracks Signals and re-runs when they change.

Resource

Bases: Generic[R]

Async resource wrapper with Signals for data, error, and loading.

Use reload() to (re)fetch, cancel() to cancel the in-flight request. Optionally accepts a source getter; when the source signal changes the resource automatically refetches.

Signal

Bases: Generic[T]

Mutable container that notifies subscribed computations on changes.

batch()

Batch signal updates within the returned context manager.

computed(fn)

Create a computed value that derives from other signals.

create_effect(fn)

Create an auto-tracking reactive effect.

The effect runs immediately and re-runs whenever any signal read inside fn changes. on_cleanup may be called inside fn to register per-run cleanup (runs before re-execution and on disposal).

If fn accepts a positional parameter, the previous return value is passed on each re-execution (None on the first run), matching SolidJS createEffect(prev => ...)::

create_effect(lambda prev: (print("was", prev), count())[1])

Inside a component, the effect is automatically disposed on unmount.

create_memo(fn)

Create an auto-tracking computed value. Returns a getter function.

Re-computes only when signals read inside fn change. Inside a component, the underlying computation is disposed on unmount.

Example::

doubled = create_memo(lambda: count() * 2)
print(doubled())  # reactive read

create_resource(source_or_fetcher, fetcher=None)

Create an async Resource with loading/error states and cancellation.

Can be called two ways:

  • create_resource(fetcher) -- simple fetcher, no source signal.
  • create_resource(source, fetcher) -- refetches automatically when the source getter's return value changes.

The fetcher should be an async function returning the data value. If it accepts a signal keyword argument, an AbortSignal will be passed for cancellation support when available.

create_root(fn)

Run fn with an independent reactive root.

fn receives a dispose callback that tears down all effects created inside the root::

result = create_root(lambda dispose: ...)

create_signal(value)

Create a reactive signal. Returns (getter, setter).

Works inside or outside components. Inside a stateful component the signal is captured by the render function's closure and persists naturally (no cursor system needed).

Example::

count, set_count = create_signal(0)
print(count())          # 0
set_count(5)
print(count())          # 5

effect(fn)

Run a reactive effect and return its computation handle.

get_props()

Return a reactive getter for the current component's props.

Useful in stateful components that need to react to parent prop changes::

props = get_props()
create_effect(lambda: print("query changed:", props()["query"]))

merge_props(*sources)

Merge multiple prop dicts. Later sources win on conflict.

Example::

defaults = {"size": "md", "variant": "solid"}
final = merge_props(defaults, props)

on(deps, fn, defer=False)

Create an effect with explicit dependencies.

deps is a single getter or a list of getters. fn receives the current value(s) as positional arguments. Only the listed deps are tracked; the body of fn is run inside untrack.

When defer is True the effect skips the first execution (useful for reacting only to changes, not the initial value).

Example::

on(count, lambda v: print("count is now", v))

on_cleanup(fn)

Register a cleanup callback.

  • Inside create_effect: runs before each re-execution and on disposal.
  • Inside a component's setup phase: runs when the component unmounts.

on_effect_cleanup(comp, fn)

Register a cleanup callback to run when a computation is disposed.

on_mount(fn)

Register a callback to run once after the component mounts.

Must be called during a component's setup phase (the body of a @component function, before the return).

signal(value)

Create a new Signal with the given initial value.

split_props(props, *key_groups)

Split a props dict into groups by key name, plus a rest dict.

Returns (group1, group2, ..., rest) where rest contains keys not claimed by any group.

Example::

local, rest = split_props(props, ["class", "style"])

untrack(fn)

Run fn without tracking any signal reads.

Useful inside effects when you need to read a signal without creating a dependency::

create_effect(lambda: print("a changed:", a(), "b is:", untrack(b)))

Public API

  • create_signal(value) -> (getter, setter)
  • create_effect(fn) -> Computation — supports previous value: create_effect(lambda prev: ...)
  • create_memo(fn) -> getter
  • on_mount(fn) — run after first render
  • on_cleanup(fn) — run on unmount or before effect re-execution
  • batch() -> context manager
Resources
  • create_resource(fetcher) -> Resource
  • create_resource(source, fetcher) -> Resource — refetches when source changes
Reactive utilities
  • untrack(fn) — run without tracking signal reads
  • on(deps, fn, defer=False) — effect with explicit deps
  • create_root(fn) — independent reactive scope
  • merge_props(*sources) — merge prop dicts
  • split_props(props, *key_groups) — split props by key name

Type hints are provided for all public functions and classes.