Shiny reactivity

Shiny

Learn about reactivity

Author

Chi Zhang

Published

July 14, 2025

Reactive programming

Key idea: specify a graph of dependencies, so that when an input changes, all related output are updated automatically.

Usual way in R: procedural. You tell what to do and when. Imperative programming

n <- 1
result <- 1 + n
n <- 2
result <- 1 + n

Reactive programming: define how to do something; when the right condition meets. Declarative programming

result <- reactive({
  1 + input$n
})

Server function

This is how a skeleton of shiny app looks like:

library(shiny)

ui <- fluidPage(
  # front end interface
)

server <- function(input, output, session) {
  # back end logic
}

shinyApp(ui, server)

In the UI part, every user gets the same UI. Not every user gets the same server: user A moves a slider doesn’t affect user B. Each session has a unique state, isolating the variables created inside the function. Almost all the reactive programming are inside the server function.

Reactivity

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

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

Run the app

Every time the input$name changes, the output also changes. The reactivity simply means that every time a user updates the browser input, the developer does not need to re-run the program. The output is automatically updated by itself.

My understanding: the developer only needs to develop the reactive code, then leaves everything to the user. The program reacts to the input

Order of execution

Reactive graph: describes how inputs and outputs are connected.

Reactive context

Reactive values can only be used inside reactive contexts. Access reactive values outside reactive context will lead to an error. E.g.

server <- function(input, output){
  print(input$num)
}
# this results in an error, as 'print' is not a reactive context
  • Any render*() is a reactive context
  • Use observe({...}) access reactive variable: it is a reactive context
# this is the correct way to print
server <- function(input, output){
  observe({ 
    print(input$num) # put in the reactive context
  })
  
}

Reactive expressions / variables

Can create a reactive variable using reactive({}), which is a reactive context.

The order of these two lines below doesn’t matter.

server <- function(input, output, session) {
  
  # define a reactive expression here
  string <- reactive(paste0("Hello ", input$name, "!"))
  # can not simply do the line below:
  # paste0("Hello ", input$name, "!")
  
  # call it 
  output$greeting <- renderText(string())
}

Access custom reactive variables like a function: need the (). For example, call string() rather than string.

server <- function(input, output){
  # create a reactive variable
  x <- reactive({
    input$num + 1
  })  

  observe({
    print(input$num)
    print(x()) # with ()
  })
}