Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
351 views
in Technique[技术] by (71.8m points)

R Shiny: reactiveValues vs reactive

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)
    
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...