R Shiny: reactiveValues vs reactive

有些话、适合烂在心里 提交于 2019-11-26 08:45:26

问题


This question is related to this one. The two can generate the same functionality, but implementation is slightly different. One significant difference is that a reactiveValue is a container that can have several values, like input$. In shiny documentation functionality is usually implemented using reactive(), but in most cases I find reactiveValues() more convenient. Is there any catch here? Are there any other major differences between the two that I might not be aware off? Are these two code snippets equivalent?

See the same example code implemented using:

  1. a reactive expression:

    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)
    
  2. a reactive value:

    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)
    

回答1:


There is a catch, though it won't come into play in your example.

The shiny developers designed reactive() to be lazy, meaning that the expression contained in it will only be executed when it is called by one of its dependents. When one of its reactive dependencies is changed, it clears its cache and notifies its own dependents, but it is not itself executed until asked to by one of those dependents. (So if, say, its sole dependent is a textOutput() element on a hidden tab, it won't actually be executed unless and until that tab is opened.)

observe(), on the other hand, is eager; the expression that it contains will be executed right away whenever one of its reactive dependencies is changed -- even if it's value is not needed by any of its dependents (and in fact even if has no dependents). Such eagerness is desirable when you're calling observe() for its side-effects, but it can be wasteful when you're only using it to pass on the return value of its contents to other reactive expressions or endpoints down the line.

Joe Cheng explains this distinction quite well in his 2016 Shiny Developer Conference presentation on "Effective reactive programming", available here. See especially the bit starting around 30:20 in the presentation's second hour. If you watch until 40:42 (blink and you'll miss it!) he briefly characterizes the behavior of the observe()/reactiveValue () combination that you like.




回答2:


It's true that the two constructs are similar, and that many times you can use either one to solve your problem. But it usually makes more sense to use one or the other.

In the fibonacci case, I think using a reactive() expression makes more sense, because currentFib is a value that should be modified in very specific predictable times (ie. when input$n changes, the reactive value should be updated accordingly, or react to that change).

But in some other cases it might be simpler and better to use reactiveValues. I will show two examples.

First, whenever you have a variable that you think of as having some sort of state (rather than just reacting to a different value being updated), I think using reactiveValues is better.

Example:

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)

In the code above, we have a total variable that has mutable state, and it's much more intuitive to think of it as a typical variable and use it as such. This is the most common case when I use reactiveValues.

I also use reactiveValues when a variable can be updated in multiple places. To borrow from the fibonacci example, consider the following shiny app, where the n number can be set by either one of two inputs:

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)

This example might seem a bit strange in the context of fibonacci, but hopefully you can see how in some other complex apps, sometimes you may wish to set the value of a variable in different places and it can be more intuitive to do it using a reactiveValue rather than a reactive expression that must be implemented in one block.

Hopefully this was helpful and makes sense. Of course this is only my personal take on the subject, it's not necessarily what the shiny developers intended, but this is how I've learned to use the two methods.



来源:https://stackoverflow.com/questions/39436713/r-shiny-reactivevalues-vs-reactive

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!