自动恢复本地最后一个Shiny书签:解决绘图更新与覆盖问题
解决方案
1. 解决绘图持续更新的主要问题
原代码通过JS跳转实现书签恢复,会导致应用重新加载并重复触发恢复逻辑,进而引发绘图的持续更新。改为在服务器初始化时直接调用session$restoreState()加载最后一个书签,无需页面跳转,从根源避免重复渲染。
2. 解决书签覆盖的次要问题
每次保存书签前,删除shiny_bookmarks目录下的所有旧书签文件,确保只保留最新的一个,避免文件堆积。
修改后的完整代码
library("shiny") library("shinyjs") library("tidyverse") ## module to do something with the data shinyModuleUserInterface <- function(id, label) { ns <- NS(id) tagList( titlePanel("Track of individual"), selectInput(inputId = ns("indv"), label = "Select indivdual", choices = c("A","B","C"), selected="A"), plotOutput(ns("plot")) ) } shinyModule <- function(input, output, session) { ns <- session$ns dataTrk <- data.frame(indv=rep(c("A","B","C"), each=4), x=c(1,4,2,6,9,5,3,8,9,4,3,7), y=c(7,5,9,3,1,2,6,4,9,5,1,6)) output$plot <- renderPlot({ plot(y~x, dataTrk[dataTrk$indv==input$indv,], type="l") }) } ## function to get the last bookmark saved get_last_bookmark <- function(){ list.files(path = 'shiny_bookmarks/') %>% map_df(., ~paste0('shiny_bookmarks/', .x) %>% file.info) %>% slice_max(atime) %>% rownames() } get_last_bookmark <- possibly(get_last_bookmark, otherwise = '') #avoid empty folder error ## main app code ui <- function(request) { fluidPage( useShinyjs(), shinyModuleUserInterface("shinyModule"), bookmarkButton() ) } server <- function(input, output, session) { callModule(shinyModule,"shinyModule") onBookmarked(function(state){ # 保存新书签前,删除所有旧书签文件 old_bookmarks <- list.files(path = 'shiny_bookmarks/', full.names = TRUE) file.remove(old_bookmarks[old_bookmarks != state$dir]) # 关闭默认弹窗,改用简洁通知 showNotification("书签已保存", type = "message", duration = 1) }) # 服务器启动时直接恢复最后一个书签 observe({ req(get_last_bookmark() != "") session$restoreState(get_last_bookmark()) }, once = TRUE) } shinyApp(ui, server, enableBookmarking="server")
关键说明
- 绘图持续更新问题解决:通过
session$restoreState()在服务器端直接加载书签状态,无需页面跳转,避免了重复触发响应式计算,绘图只会在恢复完成后渲染一次。 - 书签覆盖问题解决:在
onBookmarked回调中,删除除当前新书签外的所有旧文件,确保shiny_bookmarks目录下始终只有一个最新书签,避免文件堆积。
内容的提问来源于stack exchange,提问作者AnneScharf
相关产品推荐
相关产品推荐

