【问题标题】:Shiny: How to prevent input duplicates when rendering outputs?Shiny:渲染输出时如何防止输入重复?
【发布时间】:2019-08-15 02:39:11
【问题描述】:

在以下示例中,似乎创建了重复的输入元素,尽管每次登录/注销都会重新呈现 output$app

library(shiny)

user <- reactiveValues(logged_on = 0)

ui <- fluidPage(
  uiOutput("app")
)

server <- function(input, output) {

  observe({
    if (user$logged_on == 1) {
      output$app <- renderUI({
        list(
          uiOutput("container1"),
          uiOutput("container2")
        )
      })
      output$container1 <- renderUI({
        actionButton("logout", "Logout")
      })
      output$container2 <- renderUI({
        actionButton("clickme", "Click Me")
      })

      observeEvent(input$clickme, {
        print("got clicked!")
      })

      observeEvent(input$logout, ignoreInit = TRUE, {
        user$logged_on <- 0
      })

    } else {

      output$app <- renderUI({
        actionButton("login", "Login")
      }) 

      observeEvent(input$login, ignoreInit = TRUE, {
        user$logged_on <- 1
      })

    }

  })
}

shinyApp(ui, server)

单击Login 后跟Click Me 会提示got clicked! 一次。但是通过Logout>Login>Click Me重复该过程后提示消息两次,以此类推。

使用...检查此问题

      x <- reactiveValuesToList(input)
      print(x)

...确认创建了输入元素的副本。为什么会发生这种情况,我该如何预防?

【问题讨论】:

    标签: r shiny reactive


    【解决方案1】:

    我认为这是因为您的观察中有观察事件。这不是必需的,我已经编辑了您的代码,现在重复项似乎已被删除。 (这里也不需要ignoreInits。)

    library(shiny)
    
    user <- reactiveValues(logged_on = 0)
    
    ui <- fluidPage(
        uiOutput("app")
    )
    
    server <- function(input, output) {
    
        observe({
            if (user$logged_on == 1) {
                output$app <- renderUI({
                    list(
                        uiOutput("container1"),
                        uiOutput("container2")
                    )
                })
                output$container1 <- renderUI({
                    actionButton("logout", "Logout")
                })
                output$container2 <- renderUI({
                    actionButton("clickme", "Click Me")
                })
    
            } else {
    
                output$app <- renderUI({
                    actionButton("login", "Login")
                }) 
    
            }
    
        })
    
        observeEvent(input$clickme, {
            print("got clicked!")
        })
    
        observeEvent(input$logout, {
            user$logged_on <- 0
        })
    
        observeEvent(input$login, {
            user$logged_on <- 1
        })
    }
    
    shinyApp(ui, server)
    

    【讨论】:

    • 谢谢,这解决了问题:) 我仍然不明白为什么会这样。有什么想法吗?
    • 我能想到的只是它与观察中的观察事件有关。我猜是一些递归业务......
    【解决方案2】:

    所以我发现将observeEvent() 相互嵌套会注册新的观察者并导致问题。比我之前的例子更好的例子是:

    library(shiny)
    
    ui <- fluidPage(
      actionButton("clicks", "Click"),
      actionButton("more_clicks", "Print")
    )
    
    server <- function(input, output) {
    
      observeEvent(input$clicks,{
        observeEvent(input$more_clicks, {
          print("Hello") # you can see these piling up in the console when switching buttons
        })
      })
    }
    
    shinyApp(ui, server)
    

    我的猜测是应该尽可能避免这种情况,尽管如果子观察者在触发后被销毁,observeEvent() 可以嵌套。这可以通过参数observeEvent(eventExpr, handlerExpr, once = TRUE) 来完成。

    【讨论】:

      猜你喜欢
      • 2019-04-10
      • 1970-01-01
      • 2019-04-18
      • 2015-08-30
      • 1970-01-01
      • 2021-01-17
      • 2019-06-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多