【问题标题】:renderUI not evaluated until it is renderedrenderUI 在渲染之前不会被评估
【发布时间】:2019-12-22 05:53:08
【问题描述】:

我正在创建一个闪亮的应用程序,其中的 selectInput 动态填充了通过 renderUI 创建的反应函数。 selectInput 位于单独的“配置”选项卡面板中。 我注意到在运行应用程序后 input$id 值保持为 NULL,直到我单击 uiOutput() 所在的 tabPanel。然后在渲染之后,为 input$id 分配“选定”值。

我尝试在需要的地方使用 req(input$id) 但它不起作用。如果我尝试在调试控制台中运行 req(input$id) ,则返回的错误只是“错误:”。我也尝试使用 shinydashboard,但得到了相同的行为。

我创建了一个可重现的最小示例。 tabPanel "A" 中的 textOutput 应该显示 selectInput 的选择。但在您点击第二个 tabPanel 之前,它什么也没有显示。

library(shiny)

ui <- fluidPage(
  tabsetPanel(
    tabPanel("one", textOutput('text')),
    tabPanel("two",
             uiOutput('select'))
  )
)

server <- function(input, output, session) {
  c <- reactive({
    list("A", "B", "C")
  })

  output$select <- renderUI({
    selectInput(
      inputId = "choice",
      label = "Select input",
      choices = c(),
      selected = 1
    )
  })

  output$text <- renderText(
    input$choice
  )
}

shinyApp(ui, server)

如果我直接在第二个 tabPanel 中放置了一个 selectInput(没有 renderUI),那么 input$choice 会从应用程序开始初始化

例如

library(shiny)

ui <- fluidPage(
  tabsetPanel(
    tabPanel("one", textOutput('text')),
    tabPanel("two",
             selectInput(
               inputId = "choice",
               label = "Select input",
               choices = c("A", "B", "C"),
               selected = 1
             ))
  )
)

server <- function(input, output, session) {

  output$text <- renderText({
    input$choice
  })
}

shinyApp(ui, server)

有什么方法可以“初始化”renderUI 元素而无需加载它的 tabPanel?

谢谢

【问题讨论】:

  • 添加到服务器:outputOptions(output, "choice", suspendWhenHidden = FALSE)
  • 谢谢。这有效,但前提是放置在服务器中的输出分配之后。我想我更喜欢这种方法,因为涉及的代码更少。

标签: r shiny


【解决方案1】:

这是因为闪亮的延迟加载。

看看RStudios article on reactivity:

但是,您必须告诉 R 运行表达式才能发生这种情况,因为 R 使用一种称为惰性求值的执行方式。换句话说,R 不会执行表达式,直到你强制它执行。

因此,您必须强制 renderUI 进行评估。这意味着您的用户为您的textOutput 提供有效输入的唯一方法是使用reactive 提供一个默认值,该默认值会在input$choice 呈现后立即更新。

这里我添加了例如reactiveValues 用于反应变量 d 到您的代码:

library(shiny)

ui <- fluidPage(
  tabsetPanel(
    tabPanel("one", textOutput('text')),
    tabPanel("two",
             uiOutput('select'))
  )
)

server <- function(input, output, session) {
  c <- reactive({
    list("A", "B", "C")
  })
  d <- reactiveValues(choice = "A")

  output$select <- renderUI({
    selectInput(
      inputId = "choice",
      label = "Select input",
      choices = c(),
      selected = 1
    )
  })

  observe({
    req(input$choice)
    d$choice <- input$choice
  })

  output$text <- renderText(
    d$choice
  )
}

shinyApp(ui, server)

【讨论】:

  • 虽然这非常有效,但我更喜欢@ryan-morton 建议的方法,因为涉及的代码更少。感谢您非常快速的回答和解释
  • 我知道包含在 reactive({}) 中的表达式将被延迟执行,它像一个函数一样工作,只有在像 f() 一样调用它之后才会执行。但是 renderUI({...}) 是如何工作的呢?当然它不会像 f() 这样的语句执行。那么,它是否在用户通过 UI 修改某些内容后执行?那么有任何默认值就没有意义了。
  • reactive 急切地评估,renderUI 懒惰。因此,只要不执行renderUIreactive 就用作默认值。在这种特殊情况下,使用reactive 提供默认值是非常有意义的,而如果直接执行rendedUI 则没有意义(例如,将其移动到TabPanel 1 或将输出选项suspendWhenHidden 设置为FALSE )
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-14
  • 2020-04-18
相关资源
最近更新 更多