闪亮如何确定依赖关系

时间:2019-11-08 16:36:43

标签: r shiny shiny-reactivity

在开发应用程序时,我注意到Shiny会在不需要时重新计算输出(我认为),而且它似乎取决于reactiveValues中的嵌套。

UI:

library(shiny)
n <- 5
o <- paste0('o', 1:n)
ui <- fluidPage(
  lapply(o, function(x) textOutput(x)),
  actionButton('a1', 'a1')
)

服务器一(如我所料,重新计算输出):

server <- function(input, output){
  rv <- reactiveValues(o1='a', o2='b', o3='c', o4='d', o5='e')
  lapply(o, function(x){
    output[[x]] <- renderText({
      cat('rendering', x, '\n')
      rv[[x]]
    })
  })
  observeEvent(input$a1, {
    rv$o1 <- rnorm(1)
  })
}

服务器二(单击按钮时将重新计算每个输出):

server <- function(input, output){
  rv <- reactiveValues(
    # difference with server one is that o1-5 are nested in l
    l=list(o1='a', o2='b', o3='c', o4='d', o5='e')
  )
  lapply(o, function(x){
    output[[x]] <- renderText({
      cat('rendering', x, '\n')
      rv$l[[x]]
    })
  })
  observeEvent(input$a1, {
    rv$l$o1 <- rnorm(1)
  })
}

使用服务器一运行应用程序时,每次单击该按钮时,仅重新计算o1(如控制台中显示的那样)。但是,当在服务器2上运行该应用程序时,每次单击该按钮,都会重新计算所有输出。

我当时想知道光泽如何确定依赖关系。它可以仅区分reactiveValues的较高级别的依存关系,还是有办法使输出仅取决于reactiveValues的更深层次?换句话说,如果我需要/想要使用服务器2中的情况,是否可以防止单击按钮时重新计算o1以外的其他输出?

1 个答案:

答案 0 :(得分:1)

对于shiny的{​​{1}},每个单个对象作为一个整体是反应性组件:如果其结构内有任何东西(是否为reactiveValues,{ {1}},vector等)进行更改,则整个对象被视为已更改(因此,事物将对此做出反应)。

要讨论是否有可能对子组件做出反应,请考虑以下事项:然后将任何对象递归地视为 。对list的顶级组件做出反应的第一个示例并没有那么糟糕……但是,如果要跟踪的事物具有多个层次(并且没有理由或保障措施可以防止这种情况发生),那么每次某事发生时,让data.frame深入研究对象的每个单独组成部分都会带来很多开销。伸缩性很差。

出于组织目的,请意识到您可以具有多个独立的list组件。尽管我怀疑它是否会对性能产生很大影响,但可以这样做:

shiny

坦率地说,在某些情况下这可能会更好:紧凑性(一个超大的reactiveValues调用)可能会稍快一些(尽管我仍然不知道这是真的) ),有人可能会说 readability 直接影响 maintainability troubleshooting 。如果反应性值具有声明性分组,则在您(或其他人)几个月不活动后查看代码时,可能会有很大的不同。