嵌套结构中多次执行observeEvent的问题

snvhrwxg  于 2023-03-27  发布在  其他
关注(0)|答案(2)|浏览(147)

我正在尝试开发一个Rshinyapp,需要点击一个按钮来执行数据处理和绘图等任务。点击按钮后,UI将显示另一个按钮来分析数据和保存图像。
由于这种逻辑关系,我实现了嵌套的observeEvent来实现所需的功能,但是,现在的问题是,每次单击第二个按钮时,内部的observeEvent不仅运行一次,而且运行的次数等于第一个按钮被点击的累计次数。这种计算冗余对软件的效率有负面影响。我怎样才能解决这个问题?
在下面的简单示例中,我简化并重现了我遇到的问题。您可以尝试运行此代码并多次单击第一个和第二个按钮以观察我提到的问题。

library(shiny)

ui <- fluidPage(
  actionButton("b1", "button 1"),
  actionButton("b2", "button 2"),
)

server <- function(input, output, session) {
  x <- 1
  cat(sprintf("out x = %d \n", x))
  cat("sleep: 1s \n")
  Sys.sleep(1)  
  
  observeEvent(input$b1,{
    # Every time you click button 1, the code below will run once.
    x <<- x+1
    cat(sprintf("ob1 x = %d \n", x))
    cat("sleep: 1s \n")
    Sys.sleep(1)                           
    
    observeEvent(input$b2, {
      # Clicking button 2 once will trigger the code below to run multiple times,
      #      equal to the cumulative number of times you have clicked button 1.
      x <<- x+1
      cat(sprintf("ob2 x = %d \n", x))
      cat("sleep: 1s \n")
      Sys.sleep(1)}) 
  })
 
}

shinyApp(ui, server)

我认为这种嵌套结构是不可替代的,因为第二个按钮只有在输入正确的数据时才会显示,并且为了便于操作,输入的数据保存在observeEvent中以供使用或修改。我曾尝试用eventReactive替换observeEvent,或者添加ignoreInit = TRUE参数,但这些尝试都不起作用。
有一些类似的问题,但似乎并不能解决我的问题,你可以参考一下:ref.1ref.2
提前感谢任何试图帮助我的人。

6tdlim6h

6tdlim6h1#

扩展我的评论,这是否给予了你你所寻求的行为?

library(shiny)

ui <- fluidPage(
  actionButton("b1", "Button 1"),
  uiOutput("dynamicUI")
)

server <- function(input, output) {
  rv <- reactiveValues(button1Clicked=FALSE, x=0, y=0)

  observeEvent(input$b1, {
    rv$button1Clicked <- TRUE
    rv$x <- rv$x + 1
  })

  output$dynamicUI <- renderUI({
    if (rv$button1Clicked) {
      actionButton("b2", "Button 2")
    }
  })

  observeEvent(input$b2, {
    rv$y <- rv$y + 1
    print("Button 2 clicked")
    print(paste0("The value of x is ", rv$x))
    print(paste0("The value of y is ", rv$y))
  })
}

shinyApp(ui, server)
xqkwcwgp

xqkwcwgp2#

ref.2的启发,我对自己的代码进行了修改。这个修改解决了我上面提到的问题。
在修改后的版本中,我添加了一个变量来记录执行的次数,并用它来标识和跳过重复运行的部分,详细代码如下。
然而,正如@Limey所指出的,可能需要避免嵌套结构,我的代码仅供参考。

library(shiny)

ui <- fluidPage(
  actionButton("b1", "button 1"),
  actionButton("b2", "button 2"),
)

server <- function(input, output, session) {
  cat("begin \n")
  b1.times <- reactiveVal(1)
  b2.times <- reactiveVal(1)
  
  observeEvent(input$b1,{
    # section b1
    cat(sprintf("b1 value: %d \n", input$b1))
    cat(sprintf("b1 times: %d \n", b1.times()))
    cat("sleep: 1s \n")
    Sys.sleep(1)
    cat("--------------------------------------\n")
    
    observeEvent(input$b2, {
      # section b2
      # If the number of times that section b2 has been run does not match the value of input$b2, 
      #     then exit this section.
      if(b2.times() != input$b2) return()
      
      cat(sprintf("b1 value: %d \n", input$b1))
      cat(sprintf("b1 times: %d \n", b1.times()-1))
      cat(sprintf("b2 value: %d \n", input$b2))
      cat(sprintf("b2 times: %d \n", b2.times()))
      cat("sleep: 1s \n")
      Sys.sleep(1)
      cat("--------------------------------------\n")
      
      b2.times(b2.times()+1)  #record the number of times that section b2 has been executed.
    })
    b1.times(b1.times()+1)    #record the number of times that section b1 has been executed.
  })
}
shinyApp(ui, server)

相关问题