Suppose I have the following Shiny app (minimally-reproducible example):
global.R
# Clear environments
rm(foo.insert)
rm(.test)
if (!exists('.test')) .test <- new.env()
library(shiny)
## Setup
set.seed(1234)
.test$foo <- data.frame(replicate(10,sample(0:100,5,rep=TRUE))) # nrow(.test$foo) returns 5
foo.insert <- function(x) {
newRow <- sample(0:100,5,rep=TRUE)
newDf <- rbind(x, newRow)
assign(x = 'foo', value = newDf, envir = .test) # Add 1 row and reassign .test environment
cat(paste0(Sys.time(), ' Foo now has ', nrow(newDf), ' rows.\n'))
} # foo.insert(.test$foo)
ui.R
:
shinyUI(navbarPage(title = "TestApp",
tabPanel("Home",
withTags({
div(class="container", checked=NA,
div(class="jumbotron", checked=NA,
h4("Testing123"),
tableOutput("downloadTable")))
}),
icon = NULL),
footer = NULL
))
server.R
:
shinyServer(function(input, output, session) {
## Set up observers
updateFoo <- observe({
invalidateLater(30*1000, session = NULL) # Update every 30 seconds
foo.insert(.test$foo)
}, priority = 1)
## Reactively get the table data (to pass into the render function) every x seconds
tableData <-reactivePoll(30*1000, session = NULL,
checkFunc = function() {Sys.time()},
valueFunc = function() {
get('foo', .test)
})
output$downloadTable <- renderTable({
tableData()
}, width = '100%')
})
Here's the problem:
The loads and seems to run. I call my foo.insert()
function inside the observe
in my server definition which gets the underlying data on some interval (here, I set it to 30 seconds). Because I added the cat
output in the definition, I can confirm in the console within RStudio that it is indeed running correctly every 30s.
When I open the app inside my web browser (RStudio > Run App > Open in Browser), I notice that doing so re-runs the foo.insert()
function within my observe
as if the app was just launched. This also happens when I do a page refresh (F5) -- and is confirmed by the Sys.time()
in my function's cat
console output. In other words, every time I hit F5, it executes the function irrespective of the observer.
Obviously this is not desirable for my app (the function should run server-side every 30s regardless of what the user does). How can I fix this?