shiny
shiny copied to clipboard
Use req() in checkFunction ReactivePoll
Hi
So I have the current workflow:
A shiny app where a user signs in via Firebase. Once signed it, I have an observeEvent
that observes the sign in where a reactivevalue
changes to TRUE
value. Once this happens I want a reactivePoll
starts running to load a dataframe from a server, which needs to be refreshed based on the day. When I add req()
to checkFunction
it errors, however when I add it to valueFunction
it does work, however reactivePoll
starts running once a user opens the app without signing-in, which I do not want.
I have a simplified code with a button which is a metphore for signing in and reactivePoll
check every 30 seconds for the minute so the data changes once the button is clicked
library(shiny)
# Function to generate random data
generate_data <- function() {
data <- data.frame(
x = rnorm(10),
y = rnorm(10)
)
return(data)
}
# Define UI
ui <- fluidPage(
titlePanel("ReactivePoll Example"),
mainPanel(
actionButton("btn", "Click Me!"),
uiOutput('uioutput')
)
)
# Define server logic
server <- function(input, output, session) {
data_poll <- reactiveVal(NULL)
ready <- reactiveVal(FALSE)
# Observing the button click event
observeEvent(input$btn, {
ready(TRUE)
})
# Function to poll for updated data every 30 seconds
data_poll <- reactivePoll(
intervalMillis = 30000,
session = session,
checkFunc = function() {
# Return a timestamp to trigger polling
current_minute <- format(Sys.time(), "%M")
print(current_minute)
},
valueFunc = function() {
# Generate new data
req(ready())
generate_data()
}
)
output$uioutput = renderUI({
if (!is.null(data_poll()) && nrow(data_poll()) > 0) {
plotOutput("scatterPlot")
}
})
# Render the scatter plot
output$scatterPlot <- renderPlot({
data <- data_poll()
plot(data$x, data$y, main = "Scatter Plot", xlab = "X", ylab = "Y")
})
}
# Run the application
shinyApp(ui, server)
Hi @HugoGit39, thanks for the question! The main issue is that req()
throws an error that's normally handled gracefully by observers and reactives but that checkFunc
isn't designed to handle. You can read the reactive value in checkFunc
, though, so this pattern works:
USER_LOGGED_IN <- reactiveVal(FALSE)
observeEvent(input$login, {
message("User has logged in.")
# Pretend that the user has now logged in
USER_LOGGED_IN(TRUE)
})
# Function to poll for updated data every 30 seconds
data_poll <- reactivePoll(
intervalMillis = 5000,
session = session,
checkFunc = function() {
if (!USER_LOGGED_IN()) {
message("Not logged in yet.")
return()
}
# Return a timestamp to trigger polling
message("Data check: ", format(Sys.time(), "%H:%M:%S"))
format(Sys.time(), "%H:%M")
},
valueFunc = function() {
# Generate new data
req(USER_LOGGED_IN())
generate_data()
}
)
I've put this modification in a small shinylive app from your example.
@gadenbuie Thx!. But the checkFunc is running already from the start. Isnt there a way to start the checkFunc (or the reactivePoll function) when the user logs in?
@gadenbuie Thx!. But the checkFunc is running already from the start. Isnt there a way to start the checkFunc (or the reactivePoll function) when the user logs in?
No, the way that reactivePoll()
works is that checkFunc
should be a cheap and quick function that can be called repeatedly. Whenever its value changes, it gets a new value by calling valueFunc
.
The idea in my updated example is to have checkFunc
return immediately when the user isn't yet logged in. Because that's only checking an R object, it'll resolve immediately. So it's okay that it's running before the value of data_poll()
is actually used.
Right, but it its still a nice feature to have reactivePoll
start running after a certain period right? Does checkFunc
takes a lot of computing power on the server-side?
Right, but it its still a nice feature to have
reactivePoll
start running after a certain period right? DoescheckFunc
takes a lot of computing power on the server-side?
No, the code you use for checkFunc
should be as quick and simple as possible. The idea is that checkFunc
should run extremely quickly and be okay for Shiny to run more often than necessary without slowing down your app.