Skip to content

linked API

Use linked(...) or @linked for writable derived state: a value can be overridden manually, then reset when its source context changes.

Editor (session: default) Run
from reaktiv import linked, signal

page = signal(1)

@linked
def selection():
    return f"default-for-page-{page()}"

selection.set("custom-choice")
print(selection())  # custom-choice

page.set(2)
print(selection())  # default-for-page-2
Output Clear

Naming

Prefer linked(...) and @linked in application code. LinkedSignal is the concrete writable-derived signal class. Linked remains available as a compatibility alias.

reaktiv.linked

LinkedSignal.

LinkedDescriptor

Bases: PerInstanceDescriptor['LinkedSignal[T]'], Generic[T]

Descriptor that creates one LinkedSignal per owner instance.

LinkedSignal

Bases: ComputeSignal[T], Generic[T]

A writable signal that automatically recomputes when source signals change.

LinkedSignal combines the benefits of computed signals (automatic updates) with writable signals (can be set manually). When source signals change, it recomputes. When manually set, it holds that value until sources change again.

Perfect for form inputs, UI state, and derived values that users can override.

Parameters:

Name Type Description Default
computation_or_source Union[Callable[..., T], Signal[U], None]

The computation function (simple pattern) or source signal

None
source Optional[Union[Signal[U], Callable[[], U]]]

Optional source signal or callable (advanced pattern)

None
computation Optional[Callable[[U, Optional[PreviousState[T]]], T]]

Optional computation function (advanced pattern)

None
equal Optional[Callable[[T, T], bool]]

Optional custom equality function for change detection

None

Examples:

Simple pattern (automatic derivation):

from reaktiv import linked, signal

fahrenheit = signal(32)

# Celsius automatically computes from Fahrenheit
@linked
def celsius():
    return (fahrenheit() - 32) * 5 / 9

print(celsius())  # 0.0

fahrenheit.set(212)
print(celsius())  # 100.0

# Can override manually
celsius.set(25)
print(celsius())  # 25.0 (manual value)

# Changing source recomputes
fahrenheit.set(68)
print(celsius())  # 20.0 (recomputed from source)

Form input pattern:

from reaktiv import effect, linked, signal

# Server data
server_name = signal("John Doe")

# Form input linked to server data
@linked
def input_value():
    return server_name()

# Track changes (keep reference to prevent GC)
def print_input():
    print(f"Input: {input_value()}")

input_effect = effect(print_input)
# Prints: "Input: John Doe"

# User edits the input
input_value.set("Jane Smith")
# Prints: "Input: Jane Smith"

# Server data refreshes
server_name.set("John Updated")
# Prints: "Input: John Updated" (reset to server value)

Advanced pattern (with previous state):

from reaktiv import PreviousState, linked, signal

total_pages = signal(10)

def clamp_page(page_num, prev):
    max_page = total_pages()

    if max_page == 0:
        return None

    # First time or source changed - use default
    if prev is None or prev.source != max_page:
        return 1

    # Clamp to valid range
    return max(1, min(prev.value, max_page))

current_page = linked(
    source=total_pages,
    computation=clamp_page
)

print(current_page())  # 1 (default)

current_page.set(5)
print(current_page())  # 5

total_pages.set(3)
print(current_page())  # 3 (clamped to max)

As decorator:

from reaktiv import linked, signal

source = signal(0)

@linked
def derived():
    return source() * 2

print(derived())  # 0

source.set(5)
print(derived())  # 10

derived.set(100)
print(derived())  # 100 (manual override)

PreviousState

Bases: Generic[T]

Container for previous state in LinkedSignal computations.

Attributes:

Name Type Description
value

The previous value of the LinkedSignal

source

The previous value of the source signal

__init__(value, source)

Initialize previous state with value and source.

reaktiv.LinkedSignal

A writable signal that automatically recomputes when source signals change.

LinkedSignal combines the benefits of computed signals (automatic updates) with writable signals (can be set manually). When source signals change, it recomputes. When manually set, it holds that value until sources change again.

Perfect for form inputs, UI state, and derived values that users can override.

Parameters:

Name Type Description Default
computation_or_source Union[Callable[..., T], Signal[U], None]

The computation function (simple pattern) or source signal

None
source Optional[Union[Signal[U], Callable[[], U]]]

Optional source signal or callable (advanced pattern)

None
computation Optional[Callable[[U, Optional[PreviousState[T]]], T]]

Optional computation function (advanced pattern)

None
equal Optional[Callable[[T, T], bool]]

Optional custom equality function for change detection

None

Examples:

Simple pattern (automatic derivation):

from reaktiv import linked, signal

fahrenheit = signal(32)

# Celsius automatically computes from Fahrenheit
@linked
def celsius():
    return (fahrenheit() - 32) * 5 / 9

print(celsius())  # 0.0

fahrenheit.set(212)
print(celsius())  # 100.0

# Can override manually
celsius.set(25)
print(celsius())  # 25.0 (manual value)

# Changing source recomputes
fahrenheit.set(68)
print(celsius())  # 20.0 (recomputed from source)

Form input pattern:

from reaktiv import effect, linked, signal

# Server data
server_name = signal("John Doe")

# Form input linked to server data
@linked
def input_value():
    return server_name()

# Track changes (keep reference to prevent GC)
def print_input():
    print(f"Input: {input_value()}")

input_effect = effect(print_input)
# Prints: "Input: John Doe"

# User edits the input
input_value.set("Jane Smith")
# Prints: "Input: Jane Smith"

# Server data refreshes
server_name.set("John Updated")
# Prints: "Input: John Updated" (reset to server value)

Advanced pattern (with previous state):

from reaktiv import PreviousState, linked, signal

total_pages = signal(10)

def clamp_page(page_num, prev):
    max_page = total_pages()

    if max_page == 0:
        return None

    # First time or source changed - use default
    if prev is None or prev.source != max_page:
        return 1

    # Clamp to valid range
    return max(1, min(prev.value, max_page))

current_page = linked(
    source=total_pages,
    computation=clamp_page
)

print(current_page())  # 1 (default)

current_page.set(5)
print(current_page())  # 5

total_pages.set(3)
print(current_page())  # 3 (clamped to max)

As decorator:

from reaktiv import linked, signal

source = signal(0)

@linked
def derived():
    return source() * 2

print(derived())  # 0

source.set(5)
print(derived())  # 10

derived.set(100)
print(derived())  # 100 (manual override)

reaktiv.PreviousState

Container for previous state in LinkedSignal computations.

Attributes:

Name Type Description
value

The previous value of the LinkedSignal

source

The previous value of the source signal

__init__(value, source)

Initialize previous state with value and source.