Shiny Reactivity

Key Components of Shiny Reactivity:

Reactive Inputs:

These are user interface elements like sliders, text inputs, checkboxes, and dropdowns. When a user interacts with these elements, their values change, and Shiny recognizes these changes as triggers for reactivity.

Reactive Expressions (reactive(), eventReactive()):

These are R expressions that depend on reactive inputs or other reactive expressions. They are “lazy,” meaning they only re-execute when their dependencies change and when their value is needed by an output or another reactive expression.

  • They are defined using the reactive() function and
  • Are called like functions (e.g., my_reactive_expression()).

Reactive Outputs (render*() functions):

These are the components displayed in the user’s browser, such as plots, tables, or text. They are created using renderPlot(), renderTable(), renderText(), etc., and

  • Automatically re-render when their underlying reactive expressions or inputs change.

Observers (observeEvent(), observe()):

These are used for side effects, such as updating UI elements or writing to a database, that don’t directly produce an output to be displayed. They execute whenever their dependencies change, similar to reactive expressions,

  • but their primary purpose is to trigger actions rather than return a value.

Basic Reactivity

The ui is simple because every user gets the same HTML. The server is more complicated because every user needs to get an independent version of the app; when user A moves a slider, user B shouldn’t see their outputs change.

To achieve this independence, Shiny invokes your server() function each time a new session5 starts.

Inputs are read-only

  • Try to modify an input inside the server function, you’ll get an error:
  • If you really want to updateNumericInput() is the way but we’ll learn that later
  • input is selective about who is allowed to read it. To read from an input, you must be in a reactive context created by a function like renderText() or reactive(). (Try accessing outside of these contexts and see what happens)

Outputs

output, like input is a list-like object. But output is always used in concert with a render function.

The render function does two things:

  • It sets up a special reactive context that automatically tracks what inputs the output uses.
  • It converts the output of your R code into HTML suitable for display on a web page.

Like the input, the output is picky about how you use it. You’ll get an error if:

  • You forget the render function.
server <- function(input, output, session) {
  output$greeting <- "Hello human"
}
shinyApp(ui, server)
#> Error: Unexpected character object for output$greeting
#> ℹ Did you forget to use a render function?
  • You attempt to read from an output.
server <- function(input, output, session) {
  message("The greeting is ", output$greeting)
}
shinyApp(ui, server)
#> Error: Reading from shinyoutput object is not allowed.

Reactive Programming

Run this example:

ui <- fluidPage(
  textInput("name", "What's your name?"),
  textOutput("greeting")
)

server <- function(input, output, session) {
  output$greeting <- renderText({
    paste0("Hello ", input$name, "!")
  })
}

Imperative vs declarative programming

This difference between commands and recipes is one of the key differences between two important styles of programming:

In imperative programming, you issue a specific command and it’s carried out immediately. This is the style of programming you’re used to in your analysis scripts: you command R to load your data, transform it, visualise it, and save the results to disk.

In declarative programming, you express higher-level goals or describe important constraints, and rely on someone else to decide how and/or when to translate that into action. This is the style of programming you use in Shiny.

With imperative code you say Make me a sandwich. With declarative code you say Ensure there is a sandwich in the refrigerator whenever I look inside of it. Imperative code is assertive; declarative code is passive-aggressive.