Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use req() in checkFunction ReactivePoll #3976

Open
HugoGit39 opened this issue Jan 22, 2024 · 5 comments
Open

Use req() in checkFunction ReactivePoll #3976

HugoGit39 opened this issue Jan 22, 2024 · 5 comments

Comments

@HugoGit39
Copy link

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)





@gadenbuie
Copy link
Member

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.

@HugoGit39
Copy link
Author

HugoGit39 commented Jan 22, 2024

@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
Copy link
Member

@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.

@HugoGit39
Copy link
Author

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?

@gadenbuie
Copy link
Member

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?

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants