# ------------------------------------------------------------------- # ------------------ REACTIVES INSIDE FOR LOOPS --------------------- # ------------------------------------------------------------------- # ------------------------------------------------------------------- # --- EXAMPLE 1: this works fine, because there are no reactives in - # --- the for lopp -------------------------------------------------- # ------------------------------------------------------------------- library(shiny) ui <- fluidPage( verbatimTextOutput("txt") ) server <- function(input, output, session) { rv <- reactiveValues(one = 1, two = 2, three = 3) output$txt <- renderPrint({ vals <- list() for (val in reactiveValuesToList(rv)) { vals[[val]] <- val } for (i in seq_len(length(vals))) { print(vals[[i]]) } }) } shinyApp(ui, server) #> [1] 1 #> [1] 2 #> [1] 3 # ------------------------------------------------------------------- # --- EXAMPLE 2: this works fine, because even though there is a ---- # --- reactive in the for lopp, it is invoked immediately (inside --- # --- the for loop) ------------------------------------------------- # ------------------------------------------------------------------- library(shiny) ui <- fluidPage( verbatimTextOutput("txt") ) server <- function(input, output, session) { rv <- reactiveValues(one = 1, two = 2, three = 3) output$txt <- renderPrint({ vals <- list() for (val in reactiveValuesToList(rv)) { vals[[val]] <- reactive({ val })() } for (i in seq_len(length(vals))) { print(vals[[i]]) } }) } shinyApp(ui, server) #> [1] 1 #> [1] 2 #> [1] 3 # ------------------------------------------------------------------- # --- EXAMPLE 3: this does not work, because there is a reactive in - # --- the for lopp that is only invoked outside the for loop -------- # ------------------------------------------------------------------- library(shiny) ui <- fluidPage( verbatimTextOutput("txt") ) server <- function(input, output, session) { rv <- reactiveValues(one = 1, two = 2, three = 3) output$txt <- renderPrint({ vals <- list() for (val in reactiveValuesToList(rv)) { vals[[val]] <- reactive({ val }) } for (i in seq_len(length(vals))) { print(vals[[i]]()) } }) } shinyApp(ui, server) #> [1] 3 #> [1] 3 #> [1] 3 # --- Joe on this behavior: # --- > It's because all the iterations of the for loop share the same # --- > reference to el. So when any of the created reactive expressions # --- > execute, they're using whatever the final value of el was. # ------------------------------------------------------------------- # --- EXAMPLE 4: this works, because even though there is a reactive # --- in the for lopp that is only invoked outside of it, it is: ---- # --- ---- # --- * wrapped in a call to `local({ })`; ---- # --- ---- # --- * the iter variable (`val`) is assigned to `local({ })` ---- # --- specific variable (`myVal`); ---- # --- ---- # --- * the super-assign operator (`<-`) is used ---- # ------------------------------------------------------------------- library(shiny) ui <- fluidPage( verbatimTextOutput("txt") ) server <- function(input, output, session) { rv <- reactiveValues(one = 1, two = 2, three = 3) output$txt <- renderPrint({ vals <- list() for (val in reactiveValuesToList(rv)) { local({ myVal <- val vals[[myVal]] <<- reactive({ myVal }) }) } for (i in seq_len(length(vals))) { print(vals[[i]]()) } }) } shinyApp(ui, server) #> [1] 1 #> [1] 2 #> [1] 3 # --- Joe on this behavior: # --- > You can fix this by using a for loop but introducing a # --- > local({...}) inside of there, and creating a local variable # --- > in there whose value is assigned to el outside of the reactive. # ------------------------------------------------------------------- # --- EXAMPLE 5: this works, because we use lapply instead of a for - # --- loop ---------------------------------------------------------- # ------------------------------------------------------------------- library(shiny) ui <- fluidPage( verbatimTextOutput("txt") ) server <- function(input, output, session) { rv <- reactiveValues(one = 1, two = 2, three = 3) output$txt <- renderPrint({ vals <- lapply( reactiveValuesToList(rv), function(x) { reactive(x) } ) # --- Note that this alternative would not work because if doesn't # --- get its own reference to the iter variable, so we always --- # --- need to create a wrapper for the reactive ------------------ # vals <- lapply( # reactiveValuesToList(rv), # reactive # ) for (i in seq_len(length(vals))) { print(vals[[i]]()) } }) } shinyApp(ui, server) #> [1] 1 #> [1] 2 #> [1] 3 # --- Joe on this behavior: # --- > You can fix this by using lapply instead of a for loop; since # --- > each iteration executes as its own function call, it gets its # --- > own reference to el.