Skip to content

Instantly share code, notes, and snippets.

@bborgesr
Created March 5, 2017 19:20
Show Gist options
  • Save bborgesr/e1ce7305f914f9ca762c69509dda632e to your computer and use it in GitHub Desktop.
Save bborgesr/e1ce7305f914f9ca762c69509dda632e to your computer and use it in GitHub Desktop.

Revisions

  1. bborgesr created this gist Mar 5, 2017.
    188 changes: 188 additions & 0 deletions reactives-in-loops.R
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,188 @@
    # -------------------------------------------------------------------
    # ------------------ 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.