R Shiny:reactiveValues vs reactive

Edu*_*gel 49 r shiny

这个问题关系到这一个.这两者可以生成相同的功能,但实现略有不同.一个显着的区别是a reactiveValue是一个可以有多个值的容器,比如input$.在闪亮的文档中,功能通常使用reactive(),但在大多数情况下我觉得reactiveValues()更方便.这里有捕获吗?我可能没有注意到这两者之间是否存在其他重大差异?这两个代码片段是否相同?

查看 使用以下实现的相同示例代码:

  1. 反应性表达:

    library(shiny)
    
    ui <- fluidPage( 
      shiny::numericInput(inputId = 'n',label = 'n',value = 2),
      shiny::textOutput('nthValue'),
      shiny::textOutput('nthValueInv')   
    )
    
    fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2))
    
    server<-shinyServer(function(input, output, session) {   
      currentFib         <- reactive({ fib(as.numeric(input$n)) })  
      output$nthValue    <- renderText({ currentFib() })
      output$nthValueInv <- renderText({ 1 / currentFib() })   
    })
    
    shinyApp(ui = ui, server = server)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 反应值:

    library(shiny)
    
    ui <- fluidPage( 
      shiny::numericInput(inputId = 'n',label = 'n',value = 2),
      shiny::textOutput('nthValue'),
      shiny::textOutput('nthValueInv')  
    )
    
    fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2))
    
    server<-shinyServer(function(input, output, session) { 
      myReactives <- reactiveValues()  
      observe(  myReactives$currentFib <-  fib(as.numeric(input$n))  ) 
      output$nthValue    <- renderText({ myReactives$currentFib  })
      output$nthValueInv <- renderText({ 1 / myReactives$currentFib  }) 
    })
    
    shinyApp(ui = ui, server = server)
    
    Run Code Online (Sandbox Code Playgroud)

Jos*_*ien 63

有一个问题,但在你的例子中它不会发挥作用.

光泽开发设计reactive()懒惰,这意味着当通过其家属之一称为包含在它的表达只会被执行.当其中一个反应依赖项发生更改时,它会清除其缓存并通知其自己的依赖项,但在由其中一个依赖项要求之前,它本身不会执行.(因此,如果,例如,它的唯一依赖项是textOutput()隐藏选项卡上的元素,除非并且直到该选项卡打开,否则它实际上不会被执行.)

observe()另一方面,渴望 ; 它所包含的表达式将马上每当其活性依赖的一个改变执行-即使它不需要任何依赖它的价值(而事实上,即使没有家属).当你要求它的副作用时,这种渴望是可取的,但当你只使用它将其内容的返回值传递给其他反应式表达式或端点时observe(),这可能是浪费.

郑元畅解释这种区别相当不错在"有效反应式编程"他2016闪亮的开发者大会上演示,可以在这里找到.特别是在演示文稿的第二个小时,大约30:20开始.如果你看到40:42(眨眼,你会错过它!),他会简要描述你喜欢的observe()/ reactiveValue ()组合的行为.

  • 感谢您的见解。我想最重要的信息是使用observe/reactiveValue 的效率可能会较低。但是..正如 daattali 指出的那样,在某些情况下,reactiveValues 更容易概念化/实现。应该在闪亮的文档中更好地解释它。 (2认同)

Dea*_*ali 36

确实,这两个结构是相似的,很多时候你可以用任何一个来解决你的问题.但使用其中一种通常更有意义.

在fibonacci的情况下,我认为使用reactive()表达式更有意义,因为它currentFib是一个应该在非常特定的可预测时间内修改的值(即,当input$n更改时,应该更新反应值,或对该更改作出反应).

但在其他一些情况下,它可能更简单,更好用reactiveValues.我将展示两个例子.

首先,每当你有一个你认为具有某种状态的变量时(而不仅仅是对正在更新的不同值做出反应),我认为使用reactiveValues更好.

例:

library(shiny)

ui <- fluidPage(
  "Total:",
  textOutput("total", inline = TRUE),
  actionButton("add1", "Add 1"),
  actionButton("add5", "Add 5")
)

server <- function(input, output, session) {
  values <- reactiveValues(total = 0)

  observeEvent(input$add1, {
    values$total <- values$total + 1
  })
  observeEvent(input$add5, {
    values$total <- values$total + 5
  })
  output$total <- renderText({
    values$total
  })
}

shinyApp(ui = ui, server = server)
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我们有一个total具有可变状态的变量,并且将其视为典型变量并使用它就更直观.这是我使用时最常见的情况reactiveValues.

我也可以在多个地方更新变量时使用reactiveValues.要借用斐波纳契示例,请考虑以下闪亮应用,其中n数字可以通过以下两个输入之一设置:

library(shiny)

fib <- function(n) ifelse(n < 3, 1, fib(n - 1) + fib(n - 2))

ui <- fluidPage(
  selectInput("nselect", "Choose a pre-defined number", 1:10),
  numericInput("nfree", "Or type any number", 1),
  "Fib number:",
  textOutput("nthval", inline = TRUE)
)

server <- function(input, output, session) {
  values <- reactiveValues(n = 1)

  observeEvent(input$nselect, {
    values$n <- input$nselect
  })
  observeEvent(input$nfree, {
    values$n <- input$nfree
  })
  output$nthval <- renderText({
    fib(as.integer(values$n))
  })
}

shinyApp(ui = ui, server = server)
Run Code Online (Sandbox Code Playgroud)

这个例子在fibonacci的上下文中可能看起来有点奇怪,但希望你能看到在其他一些复杂的应用程序中,有时你可能希望在不同的地方设置一个变量的值,并且可以更直观地使用reactiveValue而不是必须在一个块中实现的反应式表达式.

希望这有用并且有意义.当然这只是我对这个主题的个人看法,它不一定是闪亮的开发者想要的,但这就是我学会使用这两种方法的方式.