R shiny 中的本地持久数据存储,适用于已部署应用程序中的多个用户

Local, persistent data storage in R shiny for multiple users in deployed app

我在 R shiny 中构建了一个梦幻足球类型的选秀模拟器。为了持续保存已选择的球员,我在保存 table 时使用了全局赋值运算符 <<-,因此它可以在应用程序的其他部分成为 'seen'。该功能的简短示例如下;

library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(DT)



TeamData <- data.frame("Pick" = 1:26 , "Team" = paste("Team",1:26) , "Player" = character(26) )
Players <- paste("Player",LETTERS)

ui <-  dashboardPagePlus(collapse_sidebar = TRUE, 
                  
                  header = dashboardHeaderPlus(),
                  
                  sidebar = dashboardSidebar(collapsed = TRUE,
                                             #####  
                                             sidebarMenu(
                                               menuItem("Tab 1",tabName = "Tab_1"))
                                             #####
                  ), 
                  
                  body = dashboardBody(
                    
                    fluidRow( column(4 , 
                                     selectInput(inputId = "dropdownSelect" , choices = c(paste("Player",LETTERS[1:10])) , label = "Drop down List") , br() , 
                                     actionButton(inputId = "draftButton" , label = "Draft")) , 
                              
                              column(6 , 
                                     dataTableOutput("draftBoard"))
                              
                    )
                    
                  ) 
                  
)
                  
                  

server <- function(input, output, session) { 
  
  pick  <- reactiveValues(num = 1)
  
  # To display table upon opening
  output$draftBoard <- DT::renderDataTable({ 
    
    datatable(data = TeamData , 
              rownames = FALSE, 
              class = "row-bordered hover stripe nowrap order-column" , 
              options  = list(dom = "t",
                              columnDefs = list(list(className = 'dt-center', targets = "_all")),
                              paging = F,
                              searching = F,
                              scrollX = F, # 'background-color', '#002651'; 'border-bottom-left-radius','5px'; 
                              info = F))
    
  })
  
  observeEvent(input$draftButton, {
    
    # Using global assignment to save the drafted Player
    TeamData$Player[pick$num] <<- input$dropdownSelect 
    
    # To display table after updating choices
    output$draftBoard <- DT::renderDataTable({ 
      
      datatable(data = TeamData , 
                rownames = FALSE, 
                class = "row-bordered hover stripe nowrap order-column" , 
                options  = list(dom = "t",
                                columnDefs = list(list(className = 'dt-center', targets = "_all")),
                                paging = F,
                                searching = F,
                                scrollX = F, 
                                info = F))
      
    })
    
    # +1 to count
    pick$num <- pick$num + 1
    
    updateSelectInput(session , inputId = "dropdownSelect" , choices = setdiff(Players, TeamData$Player))
    
    
  })

}

shinyApp(ui = ui, server = server)

在使用 shinyapps.io 部署应用程序并共享 link 供其他人使用后,我发现(艰难的方式)以这种方式进行全局分配不会让应用程序按预期工作,当多人使用该应用程序时,其他人的草稿选择会出现在他们的会话中,以及许多其他问题。

阅读了 R 中的持久数据存储后,我仍然不确定如何编写应用程序代码使其能够:

a) 被应用程序的其他部分'seen';这相当于 TeamData df,可以在应用程序的其他区域保存和访问被征召者。

b) 这样当与多人共享时,每个人都有自己的本地化应用程序会话,而不会覆盖彼此的工作。

如能提供任何帮助或material,我们将不胜感激!

使用 reactivereactiveValue 来存储您的 table。它可以在您的整个应用程序中访问,但其他同时用户无法访问。下面是一个最小的例子。

这是一个很容易犯的错误。 shinyapps.io 通常会有一个 R 实例为多个用户服务。这意味着全局存储的任何内容,即使用 <<-,将影响/对该实例中的所有用户可见。

library(shiny)

ui <- fluidPage(
    
    selectInput(inputId = "drp_players", choices = paste("Player", LETTERS), label = "dropdown"), 
    
    actionButton(inputId = "btn_draft" , label = "Draft"), 
    
    tableOutput("table")
    
)

server <- function(input, output, session) {
    
    #Reactive Value to Store Dataframe
    reactives <- reactiveValues(
        
        df_draftboard = data.frame(
            pick             = seq(1:26),
            team             = paste("Team", 1:26),
            player           = "",
            stringsAsFactors = FALSE
        )
        
    )
    
    #Table Output
    output$table <- renderTable({
        
        reactives$df_draftboard
        
    })
    
    #Draft Button is Pressed
    observeEvent(input$btn_draft, {
        
        #Work out which pick number we are up to
        picknumber <- sum(reactives$df_draftboard$player != "") + 1
        
        #Add picked player to draft board
        reactives$df_draftboard$player[picknumber] <- input$drp_players
        
        #Update dropdown
        updateSelectInput(session, "drp_players", choices = setdiff(paste("Player", LETTERS), reactives$df_draftboard$player), label = "dropdown")
        
    })
    
}

shinyApp(ui, server)