是否可以在downloadHandler的内容部分中设置reactiveValues?我试过了,不理解这种行为。
一个简单的例子可能是一个计数器,显示点击下载按钮的频率:
library(shiny)
ui <- fluidPage(
downloadButton("downloadData", "Download"),
textOutput("nDownloads"),
actionButton("trig", "get number")
)
server <- function(input, output) {
# Our dataset
data <- mtcars
r.nDownloads <- reactiveValues(n=0)
output$nDownloads <- renderText({
input$trig
paste("number of downloads:", r.nDownloads$n)
})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
r.nDownloads$n <- r.nDownloads$n + 1
write.csv(data, file)
}
)
}
shinyApp(ui, server)
如果单击下载按钮,textOutput将显示为灰色,但不会更新。我添加了一个操作按钮作为触发器来强制更新renderText。令人惊讶的是(至少对我来说)有效:显示正确的数字。
因此,downloadHandler会以某种方式更改reactiveValue,但其依赖关系只会失效,而不会更新。
当然,正确的做法是将“数据” - 对象反应并在那里进行计数。但我很好奇如何解释所描述的行为。
修改
好的,现在我真的很困惑:我尝试了上面提到的内容:让“数据”反应并在那里进行计数。这不能简单地计算下载量,因为如果数据无效,则只会重新计算。
以下是一个示例,其中包含“数据”无效的附加输入:
library(shiny)
ui <- fluidPage(
numericInput("nRows", label = "nRows", min=1, max=32, value=15),
downloadButton("downloadData", "Download"),
textOutput("nDownloads")
)
server <- function(input, output) {
r.nDownloads <- reactiveValues(n=0)
# Our dataset
data <- reactive({
isolate({
r.nDownloads$n <- r.nDownloads$n + 1
})
mtcars[1:input$nRows,]
})
output$nDownloads <- renderText({
paste("number of downloads:", r.nDownloads$n)
})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(data(), file)
}
)
}
shinyApp(ui, server)
但是,我仍然看到了类似的行为:单击下载按钮会将文本显示为灰色,更改“nRows”会产生预期的下载次数(现在
现在它给我带来了实际问题:在我的真实应用程序中,可以下载相当复杂的Excel文件。在准备和格式化Excel文件时,可能会发生应该导致应用程序反应的事件。这就是下载应该触发的原因。我可以看到的替代方法是,在用户点击下载之前准备Excel文件(我想避免的,因为这可能需要几秒钟,具体取决于文件/格式的复杂性)
我错过了一些明显的东西吗?如果没有,我会很感激任何想法,下载事件如何在应用程序的其余部分触发某些内容。
答案 0 :(得分:0)
解决方案是删除reactiveValues
的隔离,因为这会阻止在触发numericInput
之前更新计数器。这是因为data()
依赖于input$nrows
。
library(shiny)
ui <- fluidPage(
numericInput("nRows", label = "nRows", min = 1, max = 32, value = 15),
downloadButton("downloadData", "Download"),
textOutput("nDownloads")
)
server <- function(input, output) {
r.nDownloads <- reactiveValues(n = 0)
# Our dataset
data <- reactive({
r.nDownloads$n <- r.nDownloads$n + 1
mtcars[1:input$nRows,]
})
output$nDownloads <- renderText({
paste("number of downloads:", r.nDownloads$n)
})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep = "")
},
content = function(file) {
write.csv(data(), file)
}
)
}
shinyApp(ui, server)
关于更深层次的问题,如果不能保证用户将下载该文件,则不断准备一个复杂的Excel文件效率低下。您可以尝试做的是:
reactive
方法(例如data()
)保存数据。prepExcel(data)
),以返回准备好的数据。downloadHandler()
的内容中,如下所示:write_xx(prepExcel(data()))
或将数据通过管道传递到write_xx
函数中,例如data() %>% prepExcel() %>% write_xx()
,其中{ {1}}是用于输出最终文件的方法,例如xx
或write_xlsx
等。我希望这会有所帮助。