Default input values inside renderUI cause reactives to execute twice on startup

When an input value is created using renderUI, the initial reactive graph completes as if the input value is NULL even if a default value is supplied. This results in all outputs dependent on the input value calculating twice at startup. Example below:

library(dplyr)
library(shiny)

ui <- fluidPage(
  uiOutput("iris_filter"),
  dataTableOutput('table')
)

server <- function(input, output, session) {
  
  output$iris_filter <- renderUI({

    selectInput(inputId = "species_filter",
                label = "Species: ",
                choices = iris %>% distinct(as.character(Species)) %>% pull(),
                multiple = T,
                selected = 'setosa')

  })
  
  output$table <- renderDataTable({
    
    iris %>%
      filter(Species %in% input$species_filter)
    
  })
  
}
  
options(shiny.reactlog = T)
shinyApp(ui, server)

Tracing through the reactive graph in this example shows the following sequence:

  1. renderUI completes
  2. input$species_filter evalutes to NULL
  3. output$table renders
  4. input$species_filter updates to 'setosa'
  5. output$table renders

Our goal is to prevent output$table from rendering twice at startup, what is the best way to do this? Is there a way to force renderUI to set the right default value during init?

add guards against NULL inputs to cause execution to stop, this is done with req()

 filter(Species %in% req(input$species_filter))

This does not work because NULL is still a valid value for this input - it is just not the value that should be set at startup.

hacky but it works :

library(dplyr)
library(shiny)

ui <- fluidPage(
  uiOutput("iris_filter"),
  dataTableOutput("table")
)

server <- function(input, output, session) {
  run_once <- reactiveVal(FALSE)

  output$iris_filter <- renderUI({
    shiny::onFlushed(fun = \(x){shiny::onFlushed(
      fun = \(x){run_once(TRUE)})})
    selectInput(
      inputId = "species_filter",
      label = "Species: ",
      choices = iris %>% distinct(as.character(Species)) %>% pull(),
      multiple = T,
      selected = "setosa"
    )
  })

  input_species_filter_wrapped <- reactive(
    {
      req(run_once())
   input$species_filter
    })
  
  output$table <- renderDataTable({
    cat("\nhere ", input_species_filter_wrapped())
    iris %>%
      filter(Species %in% input_species_filter_wrapped())
  })
}

options(shiny.reactlog = T)
shinyApp(ui, server)
```

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.