SkillAgentSearch skills...

Reaktiv

Signals for Python - inspired by Angular Signals / SolidJS. Reactive Declarative State Management Library for Python - automatic dependency tracking and reactive updates for your application state.

Install / Use

/learn @buiapp/Reaktiv
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

reaktiv

<div align="center">

reaktiv

Python Version PyPI Version PyPI Downloads Documentation Status License Checked with pyright

ko-fi

Reactive Declarative State Management Library for Python - automatic dependency tracking and reactive updates for your application state.

Website | Live Playground | Documentation | Deep Dive Article

</div>

Installation

pip install reaktiv
# or with uv
uv pip install reaktiv

reaktiv is a reactive declarative state management library that lets you declare relationships between your data instead of manually managing updates. When data changes, everything that depends on it updates automatically - eliminating a whole class of bugs where you forget to update dependent state.

Think of it like Excel spreadsheets for your Python code: when you change a cell value, all formulas that depend on it automatically recalculate. That's exactly how reaktiv works with your application state.

Key benefits:

  • 🐛 Fewer bugs: No more forgotten state updates or inconsistent data
  • 📋 Clearer code: State relationships are explicit and centralized
  • Better performance: Only recalculates what actually changed (fine-grained reactivity)
  • 🔄 Automatic updates: Dependencies are tracked and updated automatically
  • 🎯 Python-native: Built for Python's patterns with full async support
  • 🔒 Type safe: Full type hint support with automatic inference
  • 🚀 Lazy evaluation: Computed values are only calculated when needed
  • 💾 Smart memoization: Results are cached and only recalculated when dependencies change

Documentation

Full documentation is available at https://reaktiv.bui.app/docs/.

For a comprehensive guide, check out The Missing Manual for Signals: State Management for Python Developers.

Quick Start

from reaktiv import Signal, Computed, Effect

# Your reactive data sources
name = Signal("Alice")
age = Signal(30)

# Reactive derived data - automatically stays in sync
@Computed
def greeting():
    return f"Hello, {name()}! You are {age()} years old."

# Reactive side effects - automatically run when data changes
# IMPORTANT: Must assign to variable to prevent garbage collection
greeting_effect = Effect(lambda: print(f"Updated: {greeting()}"))

# Just change your base data - everything reacts automatically
name.set("Bob")  # Prints: "Updated: Hello, Bob! You are 30 years old."
age.set(31)      # Prints: "Updated: Hello, Bob! You are 31 years old."

Core Concepts

reaktiv provides three simple building blocks for reactive programming - just like Excel has cells and formulas:

  1. Signal: Holds a reactive value that can change (like an Excel cell with a value)
  2. Computed: Automatically derives a reactive value from other signals/computed values (like an Excel formula)
  3. Effect: Runs reactive side effects when signals/computed values change (like Excel charts that update when data changes)
# Signal: wraps a reactive value (like Excel cell A1 = 5)
counter = Signal(0)

# Computed: derives from other reactive values (like Excel cell B1 = A1 * 2)
@Computed
def doubled():
    return counter() * 2

# Effect: reactive side effects (like Excel chart that updates when cells change)
def print_values():
    print(f"Counter: {counter()}, Doubled: {doubled()}")

counter_effect = Effect(print_values)

counter.set(5)  # Reactive update: prints "Counter: 5, Doubled: 10"

Excel Spreadsheet Analogy

If you've ever used Excel, you already understand reactive programming:

| Cell | Value/Formula | reaktiv Equivalent | |------|---------------|-------------------| | A1 | 5 | Signal(5) | | B1 | =A1 * 2 | Computed(lambda: a1() * 2) | | C1 | =A1 + B1 | Computed(lambda: a1() + b1()) |

When you change A1 in Excel, B1 and C1 automatically recalculate. That's exactly what happens with reaktiv:

# Excel-style reactive programming in Python
a1 = Signal(5)  # A1 = 5

@Computed  # B1 = A1 * 2
def b1() -> int:
    return a1() * 2

@Computed  # C1 = A1 + B1
def c1() -> int:
    return a1() + b1()

# Display effect (like Excel showing the values)
display_effect = Effect(lambda: print(f"A1={a1()}, B1={b1()}, C1={c1()}"))

a1.set(10)  # Change A1 - everything recalculates automatically!
# Prints: A1=10, B1=20, C1=30

Just like in Excel, you don't need to manually update B1 and C1 when A1 changes - the dependency tracking handles it automatically.

graph TD
    %% Define node subgraphs for better organization
    subgraph "Data Sources"
        S1[Signal A]
        S2[Signal B]
        S3[Signal C]
    end
    
    subgraph "Derived Values"
        C1[Computed X]
        C2[Computed Y]
    end
    
    subgraph "Side Effects"
        E1[Effect 1]
        E2[Effect 2]
    end
    
    subgraph "External Systems"
        EXT1[UI Update]
        EXT2[API Call]
        EXT3[Database Write]
    end
    
    %% Define relationships between nodes
    S1 -->|"get()"| C1
    S2 -->|"get()"| C1
    S2 -->|"get()"| C2
    S3 -->|"get()"| C2
    
    C1 -->|"get()"| E1
    C2 -->|"get()"| E1
    S3 -->|"get()"| E2
    C2 -->|"get()"| E2
    
    E1 --> EXT1
    E1 --> EXT2
    E2 --> EXT3
    
    %% Change propagation path
    S1 -.-> |"1\. set()"| C1
    C1 -.->|"2\. recompute"| E1
    E1 -.->|"3\. execute"| EXT1
    
    %% Style nodes by type
    classDef signal fill:#4CAF50,color:white,stroke:#388E3C,stroke-width:1px
    classDef computed fill:#2196F3,color:white,stroke:#1976D2,stroke-width:1px
    classDef effect fill:#FF9800,color:white,stroke:#F57C00,stroke-width:1px
    
    %% Apply styles to nodes
    class S1,S2,S3 signal
    class C1,C2 computed
    class E1,E2 effect
    
    %% Legend node
    LEGEND[" Legend:
    • Signal: Stores a value, notifies dependents
    • Computed: Derives value from dependencies
    • Effect: Runs side effects when dependencies change
    • → Data flow / Dependency (read)
    • ⟿ Change propagation (update)
    "]
    classDef legend fill:none,stroke:none,text-align:left
    class LEGEND legend

Additional Features That reaktiv Provides

Lazy Evaluation - Computations only happen when results are actually needed:

# This expensive computation isn't calculated until you access it
@Computed
def expensive_calc():
    return sum(range(1000000))  # Not calculated yet!

print(expensive_calc())  # NOW it calculates when you need the result
print(expensive_calc())  # Instant! (cached result)

Memoization - Results are cached until dependencies change:

# Results are automatically cached for efficiency
a1 = Signal(5)

@Computed
def b1():
    return a1() * 2  # Define the computation

result1 = b1()  # Calculates: 5 * 2 = 10
result2 = b1()  # Cached! No recalculation needed

a1.set(6)       # Dependency changed - cache invalidated
result3 = b1()  # Recalculates: 6 * 2 = 12

Fine-Grained Reactivity - Only affected computations recalculate:

# Independent data sources don't affect each other
a1 = Signal(5)    # Independent signal
d2 = Signal(100)  # Another independent signal

@Computed  # Depends only on a1
def b1():
    return a1() * 2

@Computed  # Depends on a1 and b1
def c1():
    return a1() + b1()

@Computed  # Depends only on d2
def e2():
    return d2() / 10

a1.set(10)  # Only b1 and c1 recalculate, e2 stays cached
d2.set(200) # Only e2 recalculates, b1 and c1 stay cached

This intelligent updating means your application only recalculates what actually needs to be updated, making it highly efficient.

The Problem This Solves

Consider a simple order calculation:

Without reaktiv (Manual Updates)

class Order:
    def __init__(self):
        self.price = 100.0
        self.quantity = 2
        self.tax_rate = 0.1
        self._update_totals()  # Must remember to call this
    
    def set_price(self, price):
        self.price = price
        self._update_totals()  # Must remember to call this
    
    def set_quantity(self, quantity):
        self.quantity = quantity
        self._update_totals()  # Must remember to call this
    
    def _update_totals(self):
        # Must update in the correct order
        self.subtotal = self.price * self.quantity
        self.tax = self.subtotal * self.tax_rate
        self.total = self.subtotal + self.tax
        # Oops, forgot to update the display!

With reaktiv (Excel-style Automatic Updates)

This is like Excel - change a cell and everything recalculates automatically:

from reaktiv import Signal, Computed, Effect

# Base values (like Excel input cells)
price = Signal(100.0)      # A1
quantity = Signal(2)       # A2  
tax_rate = Signal(0.1)     # A3

# Formulas (like Excel computed cells)
@Computed  # B1 = A1 * A2
def subtotal():
    return price() * quantity()

@Computed  # B2 = B1 * A3
def tax():
    return subtotal() * tax_rate()

@Computed  # B3 = B1 + B2
def total():
    return subtotal() + tax()

# Auto-display (like Excel chart that updates automatically)
total_effect = Effect(lambda: print(f"Order total: ${total():.2f}"))

# Just change t

Related Skills

View on GitHub
GitHub Stars438
CategoryDevelopment
Updated2d ago
Forks7

Languages

Python

Security Score

100/100

Audited on Apr 7, 2026

No findings