Попробуйте эту демонстрацию:
library(shiny)
.log <- function(...) message(format(Sys.time(), format = "[ %H:%M:%S ]"), " ", ...)
.read <- function(path) if (file.exists(path)) return(readRDS(path))
shinyApp(
ui = fluidPage(
textInput("txt", "Text: "),
actionButton("btn", "Submit"),
tableOutput("tbl")
),
server = function(input, output, session) {
.log("hello world")
rv <- reactiveValues()
rv$df <- data.frame(row = 0L, word = "a", stringsAsFactors = FALSE)[0,]
observeEvent(req(input$btn), {
.log("submit!")
rv$df <- rbind(rv$df,
data.frame(row = input$btn, word = input$txt,
stringsAsFactors = FALSE))
.log("saveRDS: ", nrow(rv$df))
saveRDS(rv$df, "local.rds")
})
filedata <- reactiveFileReader(1000, session, "local.rds", .read)
output$tbl <- renderTable(filedata())
}
)
Разработка этого приложения:
- Я использую
reactiveValues
, как вы сделали, чтобы сохранить данные в памяти. (Примечание: итеративное добавление строк в кадр плохо в долгосрочной перспективе. Если это малообъемное добавление, то, вероятно, все в порядке, но оно плохо масштабируется. Каждый раз, когда добавляется строка, она копирует весь кадр, удвоение потребления памяти.) - Я предварительно заполняю
$df
кадром с нулевой строкой, только для форматирования. Ничего необычного здесь. observe
и observeEvent
не возвращают то, что вас интересует, оно должно работать полностью с побочным эффектом . Он действительно что-то возвращает, но на самом деле он имеет значение только для shiny
внутренних элементов. saveRDS
как вы, ничего особенного, но это работает. - Я добавил
shiny::reactiveFileReader
, чтобы продемонстрировать, что файл был сохранен. Когда блестящая таблица показывает обновление, это потому, что (1) данные были добавлены в базовый фрейм; (2) кадр был сохранен в файл "local.rds"
; затем (3) reactiveFileReader
заметил, что базовый файл существует и изменился, в результате чего (4) он вызвал мою функцию .read
, чтобы прочитать содержимое и вернуть ее в качестве реактивных данных в filedata
. Этот блок совершенно не нужен вообще, просто для демонстрации здесь. - Я создаю функцию
.read
для этого reactiveFileReader
, которая устойчива к файлу, который не существует первым. Если файл не существует, он невидимо возвращает NULL
. Возможно, есть лучшие способы сделать это.