闪亮:迭代React值时陷入无限循环

m0rkklqb  于 2023-06-27  发布在  React
关注(0)|答案(2)|浏览(117)

在一个闪亮的应用程序,我想选择文件和循环所有选定的文件(做的东西与他们)。所选文件的列表需要是响应式的(以允许更新)。然而,当我循环遍历文件列表(如for (val in ...))时,我最终进入了一个无限循环。当文件列表是非React性时,不会发生无限循环。我也尝试在代码中的几个点使用isolate(),但无法解决这个问题。
处理完文件列表中的所有文件后,循环应停止。有人能在这里发现问题吗?

library(shiny)
library(shinyFiles)
library(shinyFeedback)

# UI
ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      # Button for file selection
      shinyFilesButton('files', label='File select', title='Please select a file', multiple=TRUE)
    ),
    mainPanel(
      # Empty
    )
  )
)

# SERVER
server <- function(input, output) {
  # Set up reactive value
  rv <- reactiveValues()
  rv$input_file_selected <- ""
  
  observe({
    
    # File selection (server side)
    shinyFileChoose(input, 'files', root=c(root='./'))
    # Extract file names
    if(!is.null(input$files)){
      rv$input_file_selected <- parseFilePaths(c(root='./'), input$files)
      
      # If file(s) is/are selected
      if (length(rv$input_file_selected$datapath) > 0){
        
        # Define Modal Start/Stop
        modal_confirm <- modalDialog(
          HTML("Files to process: <br/> "),
          HTML(""),
          renderTable(rv$input_file_selected$datapath, colnames = F),
          HTML("Continue? <br/> "),
          title = "Do you want to proceed?",
          footer = tagList(
            actionButton("start", "OK", class="btn btn-success"),
            actionButton("stop", "Back")
          )
        )
        # Show modal
        showModal(modal_confirm)
        
        # START
        observeEvent(input$start,  {
          # Get stored file names
          files_to_do <- rv$input_file_selected$datapath
          # Reset reactive file list
          rv$input_file_selected <- ""
          
          # Remove modal
          removeModal()
          
          ### !!! Infinite loop - should stop after all files are processed !!!
          # Call each filename
          for (val in seq(1,length(files_to_do))){
            # Show info model / process file
            print(files_to_do[[val]])
            showModal(modalDialog(paste0("Doing ", val, " / ", length(files_to_do)), footer=NULL))
            Sys.sleep(1)
          }
          # Finally remove info model
          removeModal()
        })
        
        # BACK
        observeEvent(input$stop, {
          input_file_selected <- NULL
          # Just remove START/STOP modal
          removeModal()
        })
      }
    }
  })
}

# Call App
shinyApp(ui, server)
bybem2ql

bybem2ql1#

嵌套的观察者可能是问题所在。试试这个

library(shiny)
library(shinyFiles)
library(shinyFeedback)

# UI
ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      # Button for file selection
      shinyFilesButton('files', label='File select', title='Please select a file', multiple=TRUE)
    ),
    mainPanel(
      # Empty
    )
  )
)

# SERVER
server <- function(input, output) {
  # Set up reactive value
  rv <- reactiveValues()
  rv$input_file_selected <- ""
  
  observeEvent(input$files, {
    
    # File selection (server side)
    shinyFileChoose(input, 'files', root=c(root='./'))
    # Extract file names
    if(!is.null(input$files)){
      rv$input_file_selected <- parseFilePaths(c(root='./'), input$files)
    }
    
    # If file(s) is/are selected
    if (length(rv$input_file_selected$datapath) > 0){
      
      # Define Modal Start/Stop
      modal_confirm <- modalDialog(
        HTML("Files to process: <br/> "),
        HTML(""),
        renderTable(rv$input_file_selected$datapath, colnames = F),
        HTML("Continue? <br/> "),
        title = "Do you want to proceed?",
        footer = tagList(
          actionButton("start", "OK", class="btn btn-success"),
          actionButton("stop", "Back")
        )
      )
      # Show modal
      showModal(modal_confirm)
    }
    
  })
  
  # START
  observeEvent(input$start,  {
    
    # Get stored file names
    files_to_do <- rv$input_file_selected$datapath
    # Reset reactive file list
    #rv$input_file_selected <- ""
    
    # Remove modal
    #removeModal()
    print(length(files_to_do))
    ### !!! Infinite loop - should stop after all files are processed !!!
    # Call each filename
    for (val in seq(1,length(files_to_do))){
      # Show info model / process file
      print(files_to_do[[val]])
      showModal(modalDialog(paste0("Doing ", val, " / ", length(files_to_do)), footer=NULL))
      Sys.sleep(1)
    }
    # Finally remove info model
    removeModal()
  })
  
  # BACK
  observeEvent(input$stop, {
    rv$input_file_selected <- NULL
    # Just remove START/STOP modal
    removeModal()
  })
}

# Call App
shinyApp(ui, server)
mkshixfv

mkshixfv2#

这是我的版本,类似于@YBS。没有必要把shinyFileChoose放在observe里面…

library(shiny)
library(shinyFiles)
library(shinyFeedback)

# UI
ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      # Button for file selection
      shinyFilesButton('files', label='File select', title='Please select a file', multiple=TRUE)
    ),
    mainPanel(
      # Empty
    )
  )
)

# SERVER
server <- function(input, output) {
  # Set up reactive value
  rv <- reactiveValues()
  rv$input_file_selected <- ""
  rv$files_to_do <- c()
  
  shinyFileChoose(input, 'files', root=c(root='./'))
        modal_confirm <- modalDialog(
          HTML("Files to process: <br/> "),
          HTML(""),
          renderTable(rv$input_file_selected$datapath, colnames = F),
          HTML("Continue? <br/> "),
          title = "Do you want to proceed?",
          footer = tagList(
            actionButton("start", "OK", class="btn btn-success"),
            actionButton("stop", "Back")
          )
        )
        
  observeEvent(input$files, {
    req(input$files)
    
    rv$input_file_selected <- parseFilePaths(c(root='./'), input$files)
  })
  
  observeEvent(rv$input_file_selected, {
    req(rv$input_file_selected)
    
    # Show modal
    if (length(rv$input_file_selected$datapath) > 0) {
      showModal(modal_confirm)
    }
  })
  
  observeEvent(input$start,  {
    req(rv$input_file_selected)
    
    # Get stored file names
    rv$files_to_do <- rv$input_file_selected$datapath

    # Remove modal
    removeModal()
  })
  
  observeEvent(rv$files_to_do, {
    req(rv$files_to_do)
    
    for (val in seq(1,length(rv$files_to_do))){
      # Show info model / process file
      print(rv$files_to_do[[val]])
      showModal(modalDialog(paste0("Doing ", val, " / ", length(rv$files_to_do)), footer=NULL))
      Sys.sleep(1)
    }
    # Finally remove info model
    removeModal()
    # Reset reactive file list
    rv$input_file_selected <- ""
  })
}

# Call App
shinyApp(ui, server)

相关问题