Skip to content

🚧 Under Construction 🚧

This site is currently under construction. This page is generated by AI and has not undergone thorough review by a human. There may be hallucination!

In fact, for now only /, /reactive, and the llms.txt are carefully crafted by myself.

Advanced Reactivity

HMR uses push-pull reactivity: signals push notifications when updated, but derived values are lazy and only recompute when read (pulled) or when a hard puller (like an effect) forces evaluation. This creates a dependency graph where data flows from sources to consumers.

Core primitives

from reactivity import signal, state, effect, derived, memoized, batch, new_context, reactive

Patterns

1. Stable resources

Keep DB clients, ML models, sockets in modules you rarely edit or behind factories.

2. Derived for computed values

s = signal(1)
square = derived(lambda: s.get() ** 2)  # lazy

3. Effect for side effects

@effect
def logger():
    print(square())

4. Memoized for expensive calls

@memoized
def expensive():
    return sum(range(1_000_000))

5. Batch updates

a = signal(0)
b = signal(0)

with batch():
    a.set(a.get() + 1)
    b.set(b.get() + 2)

6. Context isolation

ctx = new_context()
s = signal(0, context=ctx)
@effect(context=ctx)
def _():
    print(s.get())

7. Reactive containers

reactive() creates reactive dicts, sets, lists, or object proxies with per-key/index tracking.

Async

async_effect and async_derived support asyncio/trio via pluggable task factories.

Best practices

  • Keep heavy init in stable modules or factories
  • Prefer derived/memoized over manual caching
  • Batch related updates
  • Use new_context() for isolated subsystems
  • Restart for C extensions or global state changes
  • Think of your code as a dependency graph: signals as sources, effects as consumers, derived as transformations