Advantages of reactive vs. observe vs. observeEvent
Solution 1:
First off this stuff is sort of ambiguous, and not very intuitive in some ways, it even says so on the Shiny blog!
Here is my best understanding of the topic..
Lets start with reactive
The reactive function allows a user to monitor the status of an input or other changing variable and return the value to be used elsewhere in the code. The monitoring of a reactive variable is considered lazy, "Reactive expressions use lazy evaluation; that is, when their dependencies change, they don't re-execute right away but rather wait until they are called by someone else.(Source)". You show this well in example 2, as you can call the variable inside the renderText
environment, once called the code inside the reactive call executes and re-evaluates the variable.
For science nerds, this is a lot like quantum mechanics in that by calling the reactive variable (observing it) causes it to change by re-evaluating, too much of a stretch?
Now to observe
Observe is similar reactive, the main difference is that it does not return any values to any other environment besides its own, and it is not lazy. The observe function continually monitors any changes in all reactive values within its environment and runs the code in it's environment when these values are changed. So, observe is not a "lazy" evaluation since it does not wait to be called before it re-evaluates. Again note that you cannot assign variables from observe.
For sake of experiment:
server <- function(input,output,session)({
observe({
if (input$choice == 'Hello') {
getStatus <- 'Hi there'
}
})
observe({
if (input$choice == 'Goodbye') {
getStatus <- 'See you later'
}
})
output$result <- renderText({
getStatus
})
})
shinyApp(ui = ui, server = server)
What is important to notice is that during the code executed in observe
, we can manipulate outside environment reactive variables. In your case you assign text <- reactiveValues()
and then manipulate that by calling text$result <- 'Hi there'
. We can also do things like update selectInput
choices, or other shiny widgets, but we cannot assign any non-reactive variables in this environment like our getStatus in the example above. And this idea is mentioned on the observe
documentation,
"An observer is like a reactive expression in that it can read reactive values and call reactive expressions, and will automatically re-execute when those dependencies change. But unlike reactive expressions, it doesn't yield a result and can't be used as an input to other reactive expressions. Thus, observers are only useful for their side effects (for example, performing I/O)(Source)"
Lastly, observeEvent
The best way to use observeEvent
is to think of it as a defined trigger, as in it watches one event or change in a variable, and then fires when the event happens. I most commonly use this to watch input to buttons, as that is a defined event in which I want things to happen after the button is pushed. It uses an isolate
environment which I think is the perfect name for how this function works.
Inside this environment we can call a bunch of reactive variables, but we only define one as the trigger. The main difference between observeEvent
and observe
being the trigger, as observe
runs anytime anything changes, and observeEvent
waits for the trigger. Note that this environment is similar to observe in that it does not return non-reactive variables.
Summary
Here is an example that brings all these ideas together:
library(shiny)
ui<-
fluidPage(
fluidRow(
column(4,
h2("Reactive Test"),
textInput("Test_R","Test_R"),
textInput("Test_R2","Test_R2"),
textInput("Test_R3","Test_R3"),
tableOutput("React_Out")
),
column(4,
h2("Observe Test"),
textInput("Test","Test"),
textInput("Test2","Test2"),
textInput("Test3","Test3"),
tableOutput("Observe_Out")
),
column(4,
h2("Observe Event Test"),
textInput("Test_OE","Test_OE"),
textInput("Test_OE2","Test_OE2"),
textInput("Test_OE3","Test_OE3"),
tableOutput("Observe_Out_E"),
actionButton("Go","Test")
)
),
fluidRow(
column(8,
h4("Note that observe and reactive work very much the same on the surface,
it is when we get into the server where we see the differences, and how those
can be exploited for diffrent uses.")
))
)
server<-function(input,output,session){
# Create a reactive Evironment. Note that we can call the varaible outside same place
# where it was created by calling Reactive_Var(). When the varaible is called by
# renderTable is when it is evaluated. No real diffrence on the surface, all in the server.
Reactive_Var<-reactive({c(input$Test_R, input$Test_R2, input$Test_R3)})
output$React_Out<-renderTable({
Reactive_Var()
})
# Create an observe Evironment. Note that we cannot access the created "df" outside
# of the env. A, B,and C will update with any input into any of the three Text Feilds.
observe({
A<-input$Test
B<-input$Test2
C<-input$Test3
df<-c(A,B,C)
output$Observe_Out<-renderTable({df})
})
#We can change any input as much as we want, but the code wont run until the trigger
# input$Go is pressed.
observeEvent(input$Go, {
A<-input$Test_OE
B<-input$Test_OE2
C<-input$Test_OE3
df<-c(A,B,C)
output$Observe_Out_E<-renderTable({df})
})
}
shinyApp(ui, server)
reactive
Create a variable that can be changed over time by user inputs, evaluates "lazy" meaning only when called.
observe
Continually monitor reactive events and variables, whenever ANY reactive variable is changed in the environment (the observed environment), the code is evaluated. Can change values of previously defined reactive variables, cannot create/return variables.
observeEvent
(Domino Effect)
Continually monitor ONE defined reactive variable/event (the trigger) and run the code when the the trigger is activated by change/input of that trigger. Can change values of previously defined reactive variables, cannot create/return variables.
eventReactive
Create a variable, with a defined trigger similar to observeEvent
. Use this when you want a reactive variable that evaluates due to a trigger instead of when it is called.
I hope this helps, and if I am mistaken in my understanding or there could be more clarification, feel free to edit this answer.
Solution 2:
There is already a very detailed answer, so I'll just add my own short simple two cents:
Whenever possible, stick to reactive()
rather than reactiveValues()
. Normal reactive()
works more inline with shiny's reactive programming philosophy, meaning that the reactive()
expression just tells shiny how the variable is calculated, without having to specify when. Shiny will take care of determining when to calculate it. They will get evaluated lazily (only when needed to), they will cache their value, they will work with the bookmarking feature - it's just the way shiny was designed and should always be the first choice.
With reactiveValues()
, you are now back in more imperative programming territory, not reactive. There are cases where reactive()
does not cut it and you need to use reactiveValues()
(or reactiveVal()
), but they should only be used if reactive()
won't work. For example, with reactive()
there is only one place where the variable is defined, so if you want to define the variable in multiple places, you'll need to use reactiveValues()
. For a more complete explanation on the difference between reactive()
and reactiveValues()
, you can see my answer from an old post
observe()
vs observeEvent()
: you can think of them as the same thing, but observeEvent()
is simply a shortcut for observe()
that gets triggered by certain variables, and the rest of the code is isolate()
-ed. In fact, anything you do with observeEvent()
can always be done with observe()
as well, it's two flavours of the same thing.