Computed Signal API
The Computed class creates a signal that derives its value from other signals. It automatically tracks dependencies and updates when those dependencies change.
Basic Usage
Section titled “Basic Usage”from reaktiv import Signal, Computed
# Base signalsx = Signal(10)y = Signal(20)
# Computed signal that depends on x and ysum_xy = Computed(lambda: x() + y())
print(sum_xy()) # 30
# When a dependency changes, the computed value updates automaticallyx.set(15)print(sum_xy()) # 35Creation
Section titled “Creation”Computed(compute_fn: Callable[[], T], default: Optional[T] = None, *, equal: Optional[Callable[[T, T], bool]] = None) -> ComputedSignal[T]Creates a new computed signal that derives its value from other signals.
Parameters
Section titled “Parameters”compute_fn: A function that computes the signal’s value. When this function accesses other signals by calling them, dependencies are automatically tracked.default: An optional default value to use until the first computation and when computation fails due to an error.equal: Optional custom equality function to determine if two computed values are considered equal.
Returns
Section titled “Returns”A computed signal object that can be called to get its value.
Methods
Section titled “Methods”Calling the computed signal
Section titled “Calling the computed signal”sum_xy() # equivalent to sum_xy.get()Returns the computed value, calculating it if necessary. When called within an active effect or another computed signal, it establishes a dependency relationship.
Returns: The computed value.
Note: A computed signal is lazy. It only computes its value when called, and it caches the result until dependencies change.
Advanced Methods
Section titled “Advanced Methods”The following methods are typically used internally by the library:
subscribe / unsubscribe
Section titled “subscribe / unsubscribe”These methods work the same as in regular signals and are usually used internally by the library.
Error Handling
Section titled “Error Handling”When a computed signal’s computation function raises an exception, the exception is propagated to the caller. This allows you to handle errors at the appropriate level in your application.
from reaktiv import Signal, Computed
# Base signalx = Signal(10)
# Computed signal with potential errorresult = Computed(lambda: 100 / x())
print(result()) # 10 (100 / 10)
# Set x to 0, which would cause a division by zerox.set(0)
# The exception will be propagated to the callertry: print(result())except ZeroDivisionError as e: print(f"Caught error: {e}") # Prints: "Caught error: division by zero"
# After fixing the dependency value, computation works againx.set(5)print(result()) # 20 (100 / 5)This transparent error propagation gives you full control over error handling in your application. You can:
- Use try/except blocks where you access computed values
- Let exceptions bubble up to a higher-level error handler
- Use defensive programming in your computation functions
Lazy Evaluation
Section titled “Lazy Evaluation”A key feature of computed signals is lazy evaluation. The computation function only runs:
- The first time the signal is called
- When dependencies have changed since the last computation
This means expensive computations are only performed when necessary:
from reaktiv import Signal, Computed
x = Signal(10)y = Signal(20)
def expensive_computation(): print("Computing...") return x() * y()
result = Computed(expensive_computation)
# Nothing happens yet - computation is lazy
# First access - computation runsprint(result()) # Prints: "Computing..." then "200"
# Second access - no computation needed because nothing changedprint(result()) # Just prints "200" (no "Computing..." message)
# Change a dependencyx.set(5)
# Now accessing will recomputeprint(result()) # Prints: "Computing..." then "100"