reactive.calc

reactive.calc(fn=None, *, session=MISSING)

Mark a function as a reactive calculation.

A reactive calculation is a function whose return value depends on other reactive value(s) (i.e., Inputs, Values, and other reactive calculations). Whenever a reactive value changes, any reactive calculations that depend on it are "invalidated" and automatically re-execute if called while invalid. If a reactive calculation is marked as invalidated, any other reactive calculations that recently called it are also marked as invalidated. In this way, invalidations ripple through reactive calculations that depend on each other.

Parameters

session : ‘MISSING_TYPE | Session | None’ = MISSING

A Session instance. If not provided, the session is inferred via get_current_session.

Returns

: Calc_[T] | Callable[[CalcFunction[T]], Calc_[T]]

A decorator that marks a function as a reactive calculation.

Tip

Reactive calculations should not produce any side effects; to reactively produce side effects, use effect instead.

Reactive calculations are analagous to reactive expressions in Shiny for R.

See Also

Examples

#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 400

## file: app.py
import random
import time

from shiny import App, Inputs, Outputs, Session, reactive, render, ui

app_ui = ui.page_fluid(
    ui.card(
        ui.layout_columns(
            ui.input_action_button("first", "Invalidate first (slow) computation"),
            ui.input_action_button("second", "Invalidate second (fast) computation"),
        ),
        ui.output_text_verbatim("result"),
    )
)


def server(input: Inputs, output: Outputs, session: Session):
    @reactive.calc
    def first():
        input.first()
        p = ui.Progress()
        for i in range(30):
            p.set(i / 30, message="Computing, please wait...")
            time.sleep(0.1)
        p.close()
        return random.randint(1, 1000)

    @reactive.calc
    def second():
        input.second()
        return random.randint(1, 1000)

    @render.text
    def result():
        return first() + second()


app = App(app_ui, server)