Stop reactions with isolate()
Isolation: avoiding dependency
Sometimes it’s useful for an observer/endpoint to access a reactive value or expression, but not to take a dependency on it. For example, if the observer performs a long calculation or downloads large data set, you might want it to execute only when a button is clicked.
For this, we’ll use actionButton
. We’ll define a UI that lets the user choose number of observations to generate from the normal distribution, and has an actionButton
labeled “Go!”. You can see it in action here.
The actionButton includes some JavaScript code that sends numbers to the server. When the web browser first connects, it sends a value of 0, and on each click, it sends an incremented value: 1, 2, 3, and so on.
<- pageWithSidebar(
ui headerPanel("Click the button"),
sidebarPanel(
sliderInput("obs", "Number of observations:",
min = 0, max = 1000, value = 500),
actionButton("goButton", "Go!")
),mainPanel(
plotOutput("distPlot")
) )
In our server
function, there are two items to note. First, output$distPlot
will take a dependency on input$goButton
, simply by accessing it. When the button is clicked, the value of input$goButton
increases, and so output$distPlot
re-executes.
The second is that the access to input$obs
is wrapped with isolate()
. This function takes an R expression, and it tells Shiny that the calling observer or reactive expression should not take a dependency on any reactive objects inside the expression.
<- function(input, output) {
server $distPlot <- renderPlot({
output
# Take a dependency on input$goButton
$goButton
input
# Use isolate() to avoid dependency on input$obs
<- isolate(rnorm(input$obs))
dist hist(dist)
}) }
The resulting graph looks like this:
And here’s a walkthrough of the process when input$obs
is set to 1000, and then the Go button is clicked:
In the actionButton
example, you might want to prevent it from returning a plot the first time, before the button has been clicked. Since the starting value of an actionButton
is zero, this can be accomplished with the following:
$distPlot <- renderPlot({
outputif (input$goButton == 0)
return()
# plot-making code here
})
Reactive values are not the only things that can be isolated; reactive expressions can also be put inside an isolate()
. Building off the Fibonacci example from above, this would calculate the _n_th value only when the button is clicked:
$nthValue <- renderText({
outputif (input$goButton == 0)
return()
isolate({ fib(as.numeric(input$n)) })
})
It’s also possible to put multiple lines of code in isolate()
. For example here are some blocks of code that have equivalent effect:
# Separate calls to isolate -------------------------------
<- isolate({ input$xSlider }) + 100
x <- isolate({ input$ySlider }) * 2
y <- x/y
z
# Single call to isolate ----------------------------------
isolate({
<- input$xSlider + 100
x <- input$ySlider * 2
y <- x/y
z
})
# Single call to isolate, use return value ----------------
<- isolate({
z <- input$xSlider + 100
x <- input$ySlider * 2
y /y
x })
In all of these cases, the calling function won’t take a reactive dependency on either of the input
variables.