Shiny: what is the difference between observeEvent and eventReactive?
Asked Answered
M

5

107

I read the Shiny documentation about reactive programming a few times now, but I can't properly understand the difference between observeEvent and eventReactive.

The documentation says:

Use observeEvent whenever you want to perform an action in response to an event. (Note that "recalculate a value" does not generally count as performing an action–see eventReactive for that.)

....

Use eventReactive to create a calculated value that only updates in response to an event. This is just like a normal reactive expression except it ignores all the usual invalidations that come from its reactive dependencies;

In all the situation I tried I saw no difference between using observeEvent and eventReactive (the code works just fine regardless the function I use, with no apparent impact in performances).

Can you help me figure out what is the real difference between the two? Ideally I would like a few examples showing when they are interchangeable, one when observeEvent would work but not eventReactive and vice versa.

Moluccas answered 4/11, 2015 at 10:45 Comment(0)
S
54

As @daatali is saying the two functions are used for different purposes.

ui <- shinyUI(pageWithSidebar(
  headerPanel("eventReactive and observeEvent"),
  sidebarPanel(
    actionButton("evReactiveButton", "eventReactive"),
    br(),
    actionButton("obsEventButton", "observeEvent"),
    br(),
    actionButton("evReactiveButton2", "eventReactive2")
  ),
  mainPanel(
    verbatimTextOutput("eText"),
    verbatimTextOutput("oText")
  )
))

server <- shinyServer(function(input, output) {
  etext <- eventReactive(input$evReactiveButton, {
    runif(1)
  })
  observeEvent(input$obsEventButton,{
    output$oText <- renderText({ runif(1) })
  })
  eventReactive(input$evReactiveButton2,{
    print("Will not print")
    output$oText <- renderText({ runif(1) })
  })
  output$eText <- renderText({
    etext()
  })
})

shinyApp(ui=ui,server=server) 

eventReactive creates a reactive value that changes based on the eventExpr while observeEvent simply is triggered based on eventExpr

Sundin answered 4/11, 2015 at 11:29 Comment(1)
fwiw Joe Cheng calls assigning an output from a render function from within an observer an "anti-solution" which "usually means the author has a fundamental misconception of what it means to assign a render code block to an output slot". I haven't fully grocked what this means. rstudio-pubs-static.s3.amazonaws.com/…Flocculant
V
58

It's like the difference between observe and reactive. One is intended to be run when some reactive variable is "triggered" and is meant to have side effects (observeEvent), and the other returns a reactive value and is meant to be used as a variable (eventReactive). Even in the documentation for those functions, the former is shown without being assigned to a variable (because it is intended to just produce a side effect), and the latter is shown to be assigned into a variable and used later on.

Vivi answered 4/11, 2015 at 11:13 Comment(3)
Is it possible to have a reactiveValues object "recieve" a eventReactive? From what I understand a reactiveValues is similar to a reactive, but I've only read examples of observeEvent dealing with them. Not sure if this comment is really in the scope of this thread... but if it's the case I can open a new one...Varian
Excellent note about the variable storage.Perusal
What about creating a ‘reactiveVal’ , then populating it when an event triggers the ‘observeEvent’? Counter productive? Better to use ‘eventReactive’ because it’s lazy and not looping?Booth
S
54

As @daatali is saying the two functions are used for different purposes.

ui <- shinyUI(pageWithSidebar(
  headerPanel("eventReactive and observeEvent"),
  sidebarPanel(
    actionButton("evReactiveButton", "eventReactive"),
    br(),
    actionButton("obsEventButton", "observeEvent"),
    br(),
    actionButton("evReactiveButton2", "eventReactive2")
  ),
  mainPanel(
    verbatimTextOutput("eText"),
    verbatimTextOutput("oText")
  )
))

server <- shinyServer(function(input, output) {
  etext <- eventReactive(input$evReactiveButton, {
    runif(1)
  })
  observeEvent(input$obsEventButton,{
    output$oText <- renderText({ runif(1) })
  })
  eventReactive(input$evReactiveButton2,{
    print("Will not print")
    output$oText <- renderText({ runif(1) })
  })
  output$eText <- renderText({
    etext()
  })
})

shinyApp(ui=ui,server=server) 

eventReactive creates a reactive value that changes based on the eventExpr while observeEvent simply is triggered based on eventExpr

Sundin answered 4/11, 2015 at 11:29 Comment(1)
fwiw Joe Cheng calls assigning an output from a render function from within an observer an "anti-solution" which "usually means the author has a fundamental misconception of what it means to assign a render code block to an output slot". I haven't fully grocked what this means. rstudio-pubs-static.s3.amazonaws.com/…Flocculant
C
20

I think the top level practical aspects need to be emphasized here.

  • An eventReactive creates an object that you define like reactive does, but with out usual chain-reaction behavior you get from reactive. However it is lazily evaluated and cached like the other reactives.

  • An observeEvent can not create an object that you define (it creates something else). It is immediately evaluated and not cached. It is for causing side-effects.

So if you need a data frame, or vector, or plot or something, but want to decouple from the usual reactive chain-reactions, use eventReactive.

If you just want to cause an immediate side effect, observeEvent is your ticket.

Cambridgeshire answered 8/1, 2017 at 10:34 Comment(0)
F
6

Providing the way I understand this , correct me and add more information as required . Most of the information is from https://shiny.rstudio.com/articles/action-buttons.html

  • Also may be this has been asked long ago, I had the same question while going through eventReactive() and observeEvent()
  • ObeserveEvent , being more like a trigger for an event while eventReactive , being more like a delay
  • Below I try the same code , using both the reactive functions

To build several action buttons that control the same object, combine observeEvent() calls with reactiveValues() , Here I can use two actionButtons which are working at the same time in the same code.

Code.1 Gives the effect of observeElement()

Code.2 Uses eventReactive() , but if I try to use two different actionButtons, only the latest one works the earlier button is null and did not react

  • Code 1

        library(shiny)
    
        ui<-fluidPage(
          actionButton("runif", "uniform"),
          actionButton("rnorm", "Normal"),
          hr(),
          plotOutput("plot")
        )
    
        server<-function(input, output){
          v<-reactiveValues(data=NULL)
    
          observeEvent(
            input$runif,
            {
            v$data<-runif(100)
            }
          )
    
          observeEvent(
            input$rnorm,
            {
            v$data<-rnorm(100)
            }
          )
    
          output$plot <- renderPlot(
            {
              if (is.null(v$data)) return()
              hist(v$data)
            }
          )
        }
    
    shinyApp(ui, server)
    
  • code2

       library(shiny)
    
       ui<-fluidPage(
        actionButton(inputId = "norm", label = "Normal"),
        actionButton(inputId = "unif", label = "Uniform"),
    
      #Normal
      plotOutput("hist")
    )
    
    server <- function(input, output) {
    
      dnorm <- eventReactive(input$norm, {rnorm(100)})
      dunif <- eventReactive(input$unif, {runif(100)})
    
      output$hist <- renderPlot({  
        hist(dfnorm())
      })
    
      output$hist <- renderPlot({  
        hist(dunif())
      })
    }
    
    shinyApp(ui, server)
    
Flagwaving answered 3/6, 2017 at 18:50 Comment(1)
In code2, you have a typo: hist(dfnorm()) instead of hist(dnorm())Kepner
B
3

I found this helpful for understanding eventReactive:

eventReactives are similar to reactives, they are constructed as follows:

eventReactive( event { 
code to run 
}) 

eventReactives are not dependent on all reactive expressions in their body ('code to run' in the snippet above). Instead, they are only dependent on the expressions specified in the event section.

Blockus answered 8/12, 2020 at 16:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.