Interactivity between multiple sessions of a single running R Shiny app

2k views Asked by At

I would like to build an R Shiny app that is able to pass information from one running instance to other possible running instances. I have so far found nothing that could help me with this, and I'm hoping to do it right instead of resorting to global variables and/or writing to files etc (I used global variable in my example below, which I know is a bad practice; and I suspect writing to files wouldn't be a good practice either).

So for example, suppose I have my App.R running on a server and Tim, Jack and John have it open. How to make Tim see the below, when Jack and John are also using the app simultaneously and press the button as indicated in the below example?

App.R:

library(shiny)

# Somehow interactively visible variable? (I know global variables are bad, I wouldn't want to use such)
txt <<- ""

shinyApp(
    ui = fluidPage(
        textInput("name", "User name", value="USERNAME"),
        actionButton("button", "Button"),
        htmlOutput("text")
    ),
    server = function(input, output, session){
        a <- eventReactive(input$button, {
            txt <<- paste(txt, "Button pressed by", input$name, "at", Sys.time(), "<br>")
            txt

        })
        output$text <- reactive({
            HTML(a())
        })
    }
)

Example desired output after multiple button presses from the respective users who all have an app instance running in their browsers (all had unique input$name selected but obviously an unique session id would be better):

Example user case

Any insight would be greatly appreciated, thanks!

1

There are 1 answers

3
Enzo On BEST ANSWER

I have tested your code on a shiny server instance and it works as expected: i.e I get a printout similar to the one one you ask for.

I am a bit confused re: what are you exactly looking for?

Anyway, as a general comment I would disagree that using <<- is wrong or that global variables (in general or in a shiny app) are bad.

They have their place and indeed a typical use case is to pass states across sessions / users.

An alternative is to use shiny reactiveValues as in:

 values <- reactiveValues()
 values$lognames <- ''
 ...
 ui <- (...)

 server <- function(input, output, session){

 a <- eventReactive(input$button, {
 values$lognames <- paste(values$lognames, "Button pressed by", input$name, "at", Sys.time(), "<br>")
 values$lognames
 })
...
 }

But as a general note of caution, this type of design, although possible, may ultimately bring statefulness to the app, quickly rising its complexity and kind of going against the simplicity of the reactive paradigm.

My strong recommendation is to really think carefully before every step on this road. I've had the experience of implementing shiny apps that have rapidly escalated in complexity with the proliferation of these states. I had to keep track of all the states changes leading to brittle, difficult to debug apps.