Shiny Reactivity

Examples of passing a list of reactives, reactiveValues list and reactiveValues to a shiny module. This helps explain reactivity when passing values to a shiny module. In each case we pass a value A which triggers mod A and value B which triggers mod B. The code below and output demonstrates which outputs in the shiny module are updated upon changing a value in the main app.

  • Example 1 - list of reactives. Two reactives passed to shiny module in a list. When value A is updated only mod A updates.
  • Example 2 - ReactiveValues List. Two reactives passed to shiny module in a reactive list. The individual components are not reactive themselves but the list is. This means that when one list item is changed it triggers updates for each output that implements any member of the list. When value A is updated, both mod A and mod B update.
  • Example 3 - ReactiveValues. Two reactiveValues passed to shiny module. When value A is updated only mod A updates.

Example 1 - List of Reactives

Pass two reactives (react_A and react_B) to a shiny module. react_A is attached to a reactiveVal and initially set to A. react_B is a reactive set to B. react_A is then changed to C by changing the reactiveVal.
In this setup react_A and react_B are sent to the shiny module when it is called. react_A is updated which triggers an update of the module.

Output to the console is:

1[1] "response from module A: A"
2[1] "response from module B: B"
3[1] "response from module A: C"
 1## checking reactivity - reactive list vs list of reactives
 2## list of reactives
 3library(shiny)
 4
 5## module UI
 6mod_UI <- function(id) {
 7  ns <- NS(id)
 8  tagList(
 9    uiOutput(ns("modA")),
10    uiOutput(ns("modB"))
11  )
12}
13
14## module server
15mod <- function(id, inputvar) {
16  moduleServer(
17    id,
18    function(input, output, session) {
19      output$modA <- renderUI({
20        req(inputvar$A())
21        print(paste0("response from module A: ", inputvar$A()))
22        h3(paste0("response from module A: ", inputvar$A()))
23      })
24      
25      output$modB <- renderUI({
26        req(inputvar$B())
27        print(paste0("response from module B: ", inputvar$B()))
28        h3(paste0("response from module B: ", inputvar$B()))
29      })
30    }
31  )
32}
33
34ui <- fluidPage(
35
36  mod_UI("shinymod")
37
38)
39
40server <- function(input, output, session) {
41
42  rv <- reactiveVal("A")
43
44  react_A <- reactive({
45    rv()
46  })
47
48  react_B <- reactive({
49    "B"
50  })
51
52  mod("shinymod", inputvar = list(A = reactive(react_A()), B = reactive(react_B())))
53
54  ## Update rv$A triggers refresh of modA in shiny module but not modB
55  observe({
56    rv("C")
57  })
58
59}
60
61shinyApp(ui, server)

Example 2 - ReactiveValues List

Pass a reactiveValue, rv$AB containing a list of two members (A = A and B = B) to a shiny module. One member of rv$AB is then changed so that rv$AB contains A = C and B = B.
In this setup rv$AB is sent to the shiny module when it is called. rv$AB is updated which triggers an update of the module.

Output to the console is:

1[1] "response from module A: A"
2[1] "response from module B: B"
3[1] "response from module A: C"
4[1] "response from module B: B"

Here it is clear that updating the reactiveValue triggers two updates - one for the first list member (which changed) and one for the second (which did not). This is a highly inefficient way of passing data to a module.

 1## checking reactivity - reactive list vs list of reactives
 2## reactiveValue
 3library(shiny)
 4
 5## module UI
 6mod_UI <- function(id) {
 7  ns <- NS(id)
 8  tagList(
 9    uiOutput(ns("modA")),
10    uiOutput(ns("modB"))
11  )
12}
13
14## module server
15mod <- function(id, inputvar) {
16  moduleServer(
17    id,
18    function(input, output, session) {
19      
20      output$modA <- renderUI({
21        req(inputvar()$A)
22        print(paste0("response from module A: ", inputvar()$A))
23        h3(paste0("response from module A: ", inputvar()$A))
24      })
25      
26      output$modB <- renderUI({
27        req(inputvar()$B)
28        print(paste0("response from module B: ", inputvar()$B))
29        h3(paste0("response from module B: ", inputvar()$B))
30      })
31  
32    }
33  )
34}
35
36
37ui <- fluidPage(
38
39  mod_UI("shinymod")
40
41)
42
43server <- function(input, output, session) {
44
45  rv <- reactiveValues(
46    AB = list()
47  )
48
49  observe({
50    rv$AB <- list(A = "A", B = "B")
51  })
52
53  mod("shinymod", inputvar = reactive(rv$AB))
54
55  ## Update rv$AB triggers refresh of modA and modB in shiny module
56  observe({
57    rv$AB <- list(A = "C", B = "B")
58  })
59
60}
61
62shinyApp(ui, server)

Example 3 - ReactiveValues

Pass a set of reactiveValues, rv containing two elements (A = A and B = B) to a shiny module. Change one element (A = C). In this setup rv is sent to the shiny module when it is called. rv is updated which triggers an update of the module.

Output to the console is:

1[1] "response from module A: A"
2[1] "response from module B: B"
3[1] "response from module A: C"
 1## checking reactivity - reactive list vs list of reactives
 2## reactiveValues
 3library(shiny)
 4
 5mod_UI <- function(id) {
 6  ns <- NS(id)
 7  tagList(
 8    uiOutput(ns("modA")),
 9    uiOutput(ns("modB"))
10  )
11}
12
13## module server
14mod <- function(id, inputvar) {
15  moduleServer(
16    id,
17    function(input, output, session) {
18      
19      output$modA <- renderUI({
20        req(inputvar()$A)
21        print(paste0("response from module A: ", inputvar()$A))
22        h3(paste0("response from module A: ", inputvar()$A))
23      })
24      
25      output$modB <- renderUI({
26        req(inputvar()$B)
27        print(paste0("response from module B: ", inputvar()$B))
28        h3(paste0("response from module B: ", inputvar()$B))
29      })
30  
31    }
32  )
33}
34
35ui <- fluidPage(
36
37  mod_UI("shinymod")
38
39)
40
41server <- function(input, output, session) {
42
43  rv <- reactiveValues(
44    A = "A",
45    B = "B"
46  )
47
48  mod("shinymod", inputvar = reactive(rv))
49
50  ## Update rv$A triggers refresh of modA in shiny module
51  observe({
52    rv$A <- "C"
53  })
54
55  ## Update rv$B does not trigger refresh of modB in shiny module (no change to rv$B)
56  observe({
57    rv$B <- "B"
58  })
59
60}
61
62shinyApp(ui, server)