【问题标题】:A dynamic UI with a Reactive function - How does timing work?具有反应性功能的动态 UI - 计时如何工作?
【发布时间】:2015-04-03 03:15:39
【问题描述】:

我正在使用 renderUI 创建一个“DisplayName”输入,并且我有一个名为“ReactiveTest”的反应函数,它使用 input$DisplayName。如果您运行下面的代码,您将看到“DisplayName”下拉列表调用 NameAndID(),而后者又调用 global.r 文件中的 GetDisplayName()。该调用会填充“DisplayName”下拉列表。

但是当 ReactiveTest() 尝试访问 input$DisplayName 时,它​​说 input$DisplayName 为 NULL 然后似乎第二次调用 ReactiveTest() 然后它看到了 input$DisplayName

所以当你运行代码时,你会看到时间是这样的:

[1] "Department dropdown list is being returned now"
[1] "Department dropdown list is being returned now"

Listening on http://155.0.0.1:555
[1] "DISPLAY NAME dropdown list is being returned now"
[1] "Now ReactiveTest() tries to access input$DisplayName"
[1] "ReactiveTest() says input$DisplayName Name is NULL" --> why is it NULL? if 2 lines above the dropdown was populated???
[1] "Now ReactiveTest() tries to access input$DisplayName"--> Where is this coming from? Shouldn't there only be  1 call to ReactiveTest()
[1] "ReactiveTest() says input$DisplayName Name is Bob" 

我有 3 个问题:

(1) 为什么调用 DisplayName 下拉菜单后 ReactiveTest() 看不到 input$DisplayName?

(2) 为什么要再次调用 ReactiveTest()?

(3) 如何让 ReactiveTest() 在第一次调用时看到“DisplayName”下拉列表中的内容?在我的真实代码中,我必须测试 is.null(input$DisplayName)== TRUE 然后不运行一些代码但没有更好的方法吗?

这是我可以运行的代码:

library(shiny)

runApp(list(
  ui = basicPage(
    sidebarPanel(
      selectInput("Department", "Select a department", 
                  choices = as.character(GetDepartments()$Department), 
                  selected = as.character(GetDepartments()$Department[1])),
      uiOutput("DisplayName")
    ),
    mainPanel(textOutput("Text") )
  ),
  server = function(input, output, session) {

    NameAndID<- reactive({
      GetDisplayName(input$Department)
    })

    output$DisplayName<-renderUI({
      Department <- input$Department
      selectInput("DisplayName", 'DisplayName:', choices = as.character(NameAndID()$DisplayName), selected =as.character(NameAndID()$DisplayName[1] ))
    })

    ReactiveTest<- reactive({
      print("Now ReactiveTest() tries to access input$DisplayName")
      if(is.null(input$DisplayName) == TRUE)
      {
        print("ReactiveTest() says input$DisplayName Name is NULL")
        return("NULL")
      }else
      {
        print(paste0("ReactiveTest() says input$DisplayName Name is ", input$DisplayName))
        return(input$DisplayName)
      }
    })

    output$Text <- renderText({
      #myData <- GetDisplayName(input$Department)
      #code <- as.character(myData[myData$DisplayName == input$DisplayName,2])

      return(ReactiveTest())       
    })

  }
))

global.r

GetDepartments<- function(){
  df<- data.frame(Department= c("Dept A", "Dept B"), id = c(1,2))
  print("Department dropdown list is being returned now")
  return(df)
}

GetDisplayName<- function(Dept){

  if(Dept == "Dept A")
  {
    df<- data.frame(DisplayName= c("Bob", "Fred"), id = c(4,6))
    print("DISPLAY NAME dropdown list is being returned now")
    return(df)
  }else
  {
    df<- data.frame(DisplayName= c("George", "Mary"), id = c(10,20))
    print("DISPLAY NAME dropdown list is being returned now")
    return(df)
  }

}

【问题讨论】:

    标签: r shiny


    【解决方案1】:

    您的问题基本上都是在问同一个问题,为什么函数会被调用两次?

    正如我在您之前的问题中提到的,只有当反应式表达式意识到输入中的某些内容发生了变化时,它们才会再次运行。当您使用响应式 ui 初始化闪亮的应用程序时,最初不会加载值(即空值)。这之前已经出现过其他闪亮的问题,例如 google 群组上的this one 和SO 上的类似问题,并且普遍的共识是您应该对您的代码进行某种检查(希望被证明是错误的)。因此,您添加is.null 检查的直觉是正确的。因此,这是使用validate 函数的好机会。虽然这个初始化问题有点烦人,但初始化所花费的时间应该是微不足道的。

    这是使用validate 的示例。但是,如果以某种方式传递了一个空值并且没有运行通过validate 的任何内容,这使得提供用户友好的错误消息变得非常容易。更直接地说,在反应式表达式中,初始化只打印然后离开函数。推荐使用这种类型的验证,可以在here找到文档

    runApp(list(
        ui = basicPage(
            sidebarPanel(
                selectInput("Department", "Select a department", 
                            choices = as.character(GetDepartments()$Department), 
                            selected = as.character(GetDepartments()$Department[1])),
                uiOutput("DisplayName")
            ),
            mainPanel(textOutput("Text") )
        ),
        server = function(input, output, session) {
    
            NameAndID<- reactive({
                GetDisplayName(input$Department)
            })
    
            output$DisplayName<-renderUI({
                Department <- input$Department
                selectInput("DisplayName", 'DisplayName:', choices = as.character(NameAndID()$DisplayName), selected =as.character(NameAndID()$DisplayName[1] ))
            })
    
            ReactiveTest<- reactive({
                print("Now ReactiveTest() tries to access input$DisplayName")
                validate(
                    need(!is.null(input$DisplayName), "ReactiveTest() says input$DisplayName Name is NULL")
                )
                print(paste0("ReactiveTest() says input$DisplayName Name is ", input$DisplayName))
                return(input$DisplayName)
            })
    
            output$Text <- renderText({            
                return(ReactiveTest())       
            })  
        }
    ))
    

    【讨论】:

    • 我会坚持使用 is.null 检查。
    猜你喜欢
    • 2010-12-28
    • 2021-03-27
    • 2021-01-15
    • 2019-04-30
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多