Suponha que eu tenha um reactive
que retorna um data.frame
. Quero que alguns dos meus controles tomem uma dependência somente em um subconjunto de suas colunas, ou seja, eles devem disparar somente se os valores em qualquer uma das colunas "relevantes" (aqui rel_1
e rel_2
) mudarem, enquanto as alterações nas colunas "irrelevantes" (aqui irr_1
e irr_2
) não devem disparar uma atualização.
Achei que criar um reactive
que retornasse apenas as colunas relevantes resolveria o problema, mas o código a seguir mostra que todos os botões acionam uma atualização do verbatimTextOutput
. Minha expectativa seria que pressionar para Alterar Colunas Irrelevantes não acionaria uma atualização, porque os valores nas colunas relevantes permanecem inalterados.
library(shiny)
library(DT)
library(dplyr)
library(glue)
dat <- tibble(
rel_1 = LETTERS[1:3],
rel_2 = letters[1:3],
irr_1 = 1:3,
irr_2 = 101:103
)
ui <- fluidPage(
fluidRow(
column(
width = 4,
actionButton("chng_all", "Change All Columns")
),
column(
width = 4,
actionButton("chng_irr", "Change Irrelevant Columns")
),
column(
width = 4,
actionButton("chng_rel", "Change Relevant Columns")
)
),
fluidRow(
column(
width = 12,
DTOutput("tbl")
)
),
fluidRow(
column(
width = 12,
verbatimTextOutput("dbg")
)
)
)
server <- function(input, output, session) {
my_data <- reactiveVal(dat)
change_values <- function(data, cols) {
data %>%
mutate(
across(all_of(cols),
~ if (is.numeric(.x)) sample(100, 3) else sample(LETTERS, 3))
)
}
relevant_data <- reactive(
my_data() %>%
select(starts_with("rel"))
)
observe({
my_data(change_values(my_data(), c(paste0("irr_", 1:2),
paste0("rel_", 1:2))))
}) %>%
bindEvent(input$chng_all)
observe({
my_data(change_values(my_data(), paste0("irr_", 1:2)))
}) %>%
bindEvent(input$chng_irr)
observe({
my_data(change_values(my_data(), paste0("rel_", 1:2)))
}) %>%
bindEvent(input$chng_rel)
output$tbl <- renderDT(
datatable(my_data())
)
output$dbg <- renderPrint({
glue("Relevant Data Last Changed: {Sys.time()}")
}) %>%
bindEvent(relevant_data())
}
shinyApp(ui, server)
Podemos alcançar o comportamento desejado usando a
reactiveVal
em vez dereactive
:Winston Chang explicou isso aqui da seguinte forma:
Veja também esta postagem de blog relacionada.