reactive.event
*args, ignore_none=True, ignore_init=False) reactive.event(
Mark a function to react only when an "event" occurs.
Shiny's reactive programming framework is primarily designed for calculated values (calc
) and side-effect-causing actions (effect
) that respond to any of their inputs changing. That's often what is desired in Shiny apps, but not always: sometimes you want to wait for a specific action to be taken from the user, like clicking an input_action_button
, before calculating or taking an action. You do not want the calculation or action to be prematurely triggered if other reactive values that it calls are invalidated. The reactive value (or function) which triggers other calculations or actions in this way is called an event.
These situations demand a more imperative, "event handling" style of programming, which @reactive.event()
provides. It does this by using the isolate
primitive under-the-hood to essentially "limit" the set of reactive dependencies to those in args
. In other words, the event can call as many reactive values as it likes in its code body without taking a reactive dependency on them; it will be invalidated only when a dependency listed in args is invalidated.
Parameters
*args : Callable[[],
object
] | Callable[[], Awaitable[object
]] = ()-
One or more callables that represent the event; most likely this will be a reactive input value linked to a
input_action_button
or similar (e.g.,input.click
), but it can also be a (reactive or non-reactive) function that returns a value. ignore_none : bool = True
-
Whether to ignore the event if the value is
None
or0
. ignore_init : bool = False
-
If
False
, the event triggers on the first run.
Returns
Tip
This decorator must be applied before the relevant reactivity decorator (i.e., @reactive.event
must be applied before @reactive.effect
, @reactive.calc
, @render.ui
, etc).
Examples
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 400
## file: app.py
import random
from shiny import App, Inputs, Outputs, Session, reactive, render, ui
app_ui = ui.page_fluid(
ui.markdown(
f"""
This example demonstrates how `@reactive.event()` can be used to restrict
execution of: (1) a `@render` function, (2) `@reactive.calc`, or (3)
`@reactive.effect`.
In all three cases, the output is dependent on a random value that gets updated
every 0.5 seconds (currently, it is {ui.output_ui("number", inline=True)}), but
the output is only updated when the button is clicked.
"""
),
ui.row(
ui.column(
3,
ui.input_action_button("btn_out", "(1) Update number"),
ui.output_text("out_out"),
),
ui.column(
3,
ui.input_action_button("btn_calc", "(2) Show 1 / number"),
ui.output_text("out_calc"),
),
ui.column(
3,
ui.input_action_button("btn_effect", "(3) Log number"),
ui.div(id="out_effect"),
),
),
)
def server(input: Inputs, output: Outputs, session: Session):
# Update a random number every second
val = reactive.value(random.randint(0, 1000))
@reactive.effect
def _():
reactive.invalidate_later(0.5)
val.set(random.randint(0, 1000))
# Always update this output when the number is updated
@render.ui
def number():
return val.get()
# Since ignore_none=False, the function executes before clicking the button.
# (input.btn_out() is 0 on page load, but @@reactive.event() treats 0 as None for
# action buttons.)
@render.text
@reactive.event(input.btn_out, ignore_none=False)
def out_out():
return str(val.get())
@reactive.calc
@reactive.event(input.btn_calc)
def calc():
return 1 / val.get()
@render.text
def out_calc():
return str(calc())
@reactive.effect
@reactive.event(input.btn_effect)
def _():
ui.insert_ui(
ui.p("Random number!", val.get()),
selector="#out_effect",
where="afterEnd",
)
app = App(app_ui, server)