在适用于 R 的 Shiny 应用程序中,如何延迟响应式的触发? [英] In Shiny apps for R, how do I delay the firing of a reactive?

查看:13
本文介绍了在适用于 R 的 Shiny 应用程序中,如何延迟响应式的触发?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 Shiny 应用中有一个 selectizeInput.它处于多选模式,因此用户可以指定多个选择.

I have a selectizeInput in my Shiny app. It is in multiple-select mode, so the user can specify more than one selection.

然而,每次添加选择时,依赖于 selectizeInput 的反应都会被触发.假设用户打算选择ABC.目前,我的应用程序将对选择 AA、BA、B、C 进行昂贵的计算,当只有最后一个是必需的.

However, the reactives that depend on the selectizeInput get fired every time a selection is added. Suppose that the user intends to select A, B and C. Currently, my app will do it expensive computations for the selections A, A, B and A, B, C, when only the last is required.

我认为解决这个问题的最好方法是将 selectizeInput 的触发延迟一秒左右,让用户有机会输入所有选择.每个新选择都应将计时器设置回 1 秒.我知道 Shiny 提供了一个 invalidateLater 命令,但这会导致反应性地一次又一次地触发.

The best way I can think to solve this is to delay the firing of the selectizeInput by a second or so to give the user a chance to enter all of the selections. Each new selection should set the timer back to 1 second. I know that Shiny provides an invalidateLater command, but this causes the reactive to fire once now and once later.

我怎样才能让反应在之后触发一次?

How can I get the reactive to only fire once later?

推荐答案

你应该debounce 反应性.

这里有一个 R 实现:https://gist.github.com/jcheng5/6141ea7066e62cafb31c

There is an R implementation here: https://gist.github.com/jcheng5/6141ea7066e62cafb31c

# Returns a reactive that debounces the given expression by the given time in
# milliseconds.
#
# This is not a true debounce in that it will not prevent code{expr} from being
# called many times (in fact it may be called more times than usual), but
# rather, the reactive invalidation signal that is produced by expr is debounced
# instead. This means that this function should be used when code{expr} is
# cheap but the things it will trigger (outputs and reactives that use
# code{expr}) are expensive.
debounce <- function(expr, millis, env = parent.frame(), quoted = FALSE,
  domain = getDefaultReactiveDomain()) {
  
  force(millis)
  
  f <- exprToFunction(expr, env, quoted)
  label <- sprintf("debounce(%s)", paste(deparse(body(f)), collapse = "
"))

  v <- reactiveValues(
    trigger = NULL,
    when = NULL # the deadline for the timer to fire; NULL if not scheduled
  )  

  # Responsible for tracking when f() changes.
  observeEvent(f(), {
    # The value changed. Start or reset the timer.
    v$when <- Sys.time() + millis/1000
  }, ignoreNULL = FALSE)

  # This observer is the timer. It rests until v$when elapses, then touches
  # v$trigger.
  observe({
    if (is.null(v$when))
      return()
    
    now <- Sys.time()
    if (now >= v$when) {
      v$trigger <- runif(1)
      v$when <- NULL
    } else {
      invalidateLater((v$when - now) * 1000, domain)
    }
  })

  # This is the actual reactive that is returned to the user. It returns the
  # value of f(), but only invalidates/updates when v$trigger is touched.
  eventReactive(v$trigger, {
    f()
  }, ignoreNULL = FALSE)
}


#' @examples
#' library(shiny)
#' 
#' ui <- fluidPage(
#'   numericInput("val", "Change this rapidly, then pause", 5),
#'   textOutput("out")
#' )
#' 
#' server <- function(input, output, session) {
#'   debounced <- debounce(input$val, 1000)
#'   output$out <- renderText(
#'     debounced()
#'   )
#' }
#' 
#' shinyApp(ui, server)

这篇关于在适用于 R 的 Shiny 应用程序中,如何延迟响应式的触发?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆