繁体   English   中英

使用来自 function 的反应性(闪亮)

[英]Using reactivity (in Shiny) from a function

我正在为我的应用程序编写一个 function,它将在后台调用一个进程,并监视它停止的那一刻。 关闭 session 后,进程应该被终止,所以我希望它在 function 之外可用。如果我用<<-符号分配进程,会发生一些奇怪的事情......

library(shiny)
library(processx)


runAsync <- function() {

  mainProcess <<- process$new("sleep", "10")

  procTimer <- reactivePoll(1000, NULL, 
                            checkFunc = function() 
                              mainProcess$is_alive() ,
                            valueFunc = function() 
                                mainProcess$is_alive()
                            )
  
  observeEvent(procTimer(),  {
    if(procTimer()) {print("Begin")} else {print("End")}
    print(  mainProcess)
  })
}



ui <- fluidPage(
  actionButton("runBtn", "Run async process"),
)

server <- function(input, output, session) {
  observeEvent(input$runBtn, runAsync())  
}

shinyApp(ui, server)

第一次单击该按钮时,一切都按预期进行。 output 是

[1] "Begin"
PROCESS 'sleep', running, pid #####.
[1] "End"
PROCESS 'sleep', finished.

然而,第二次,observeEvent 被触发了两次。 第三次,observedEvent 被触发了三次。 依此类推...第三次点击按钮时的output为

PROCESS 'sleep', running, pid 19228.
[1] "Begin"
PROCESS 'sleep', running, pid 19228.
[1] "Begin"
PROCESS 'sleep', running, pid 19228.
[1] "End"
PROCESS 'sleep', finished.
[1] "End"
PROCESS 'sleep', finished.
[1] "End"
PROCESS 'sleep', finished.

如果我用一个简单的<-赋值替换<<-赋值,它就修复了(至少在表面上),问题就不会发生。

所以,我的主要问题是这种行为的原因是什么? 我想明白

我还想问一个附带问题:这样的 function 有什么好的设计? 在 function 内启动 reactivePoll 是一种好习惯吗?

问题是每次调用runAsync()时都会添加一个新的observeEvent调用,一个快速修复方法是引入一个反应值来检查 function 是否已被调用,然后不添加新的observeEvent ,如该示例所示:

library(shiny)
library(processx)


runAsync <- function(start) {
  
  mainProcess <<- process$new("sleep", "10")
  
  procTimer <- reactivePoll(1000, NULL, 
                            checkFunc = function() 
                              mainProcess$is_alive() ,
                            valueFunc = function() 
                              mainProcess$is_alive()
  )
  if(isTRUE(reactive_value$start))
  {
    observeEvent(procTimer(),  {
      if(procTimer()) {print("Begin")} else {print("End")}
      print(  mainProcess)
    })
    reactive_value$start <- FALSE
  }

}

ui <- fluidPage(
  actionButton("runBtn", "Run async process"),
)
reactive_value <- shiny::reactiveValues(start = TRUE)

server <- function(input, output, session) {
  observeEvent(input$runBtn, runAsync(reactive_value))  
}

shinyApp(ui, server)

更长的解决方案是以observeEvent调用在 runAsync 之外的方式重新构建代码runAsync

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM