Aprofundamento em programação reativa
Entenda valores reativos, reativos, observadores e o grafo reativo.
Aprofundamento em programação reativa é uma aula grátis de R Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de R Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de R Academy inclui 4 aulas no total.
Reatividade: a ideia principal
O modelo de programação reativa do Shiny acompanha automaticamente as dependências entre os cálculos. Quando uma entrada muda, somente as saídas que dependem dela são executadas novamente — nada além disso. Compreender esse grafo de dependências é essencial para escrever aplicativos Shiny eficientes e sem erros.
library(shiny)
# Simplest reactive relationship:
# output depends on input — Shiny tracks this automatically
server <- function(input, output, session) {
output$result <- renderText({
paste('You typed:', input$text_in) # depends on text_in
})
}reactive({}) — Cálculos compartilhados
reactive({...}) cria uma expressão reativa cujo resultado é armazenado em cache e compartilhado. Se várias saídas usarem o mesmo cálculo caro, envolva-o em reactive() para calculá-lo uma vez a cada alteração, em vez de uma vez por consumidor. Chame-o como uma função: data_subset().
server <- function(input, output, session) {
# Computed once, shared by multiple outputs
filtered_data <- reactive({
subset(mtcars, cyl == input$cyl_select)
})
output$plot <- renderPlot({ plot(filtered_data()$wt,
filtered_data()$mpg) })
output$table <- renderTable({ filtered_data() })
# filtered_data() is only recomputed once when cyl_select changes
}reactiveVal() — Um único valor reativo
reactiveVal(initial_value) cria uma variável reativa que pode ser lida e escrita programaticamente. Leia-a chamando-a sem argumentos; escreva nela chamando-a com um novo valor. Isso é útil para armazenar um estado mutável do qual vários observadores ou saídas dependem.
server <- function(input, output, session) {
counter <- reactiveVal(0) # initial value = 0
observeEvent(input$increment, {
counter(counter() + 1) # read current, write new
})
observeEvent(input$reset, {
counter(0) # reset to 0
})
output$count <- renderText(paste('Count:', counter()))
}reactiveValues() — Várias variáveis de estado
reactiveValues(key = value, ...) funciona como uma lista nomeada em que cada elemento é reativo. Quando qualquer elemento muda, somente as saídas que leem esse elemento são invalidadas. Use-o para agrupar variáveis de estado relacionadas que são atualizadas juntas.
server <- function(input, output, session) {
state <- reactiveValues(
data = NULL,
current_page = 1,
total_rows = 0
)
observeEvent(input$load_btn, {
state$data <- read.csv(input$file$datapath)
state$total_rows <- nrow(state$data)
state$current_page <- 1
})
output$info <- renderText({
paste('Page', state$current_page, '| Rows:', state$total_rows)
})
}observeEvent() — Respondendo a eventos
observeEvent(eventExpr, handlerExpr) executa handlerExpr sempre que eventExpr é alterado. Ele é usado para efeitos colaterais: atualizar o estado, gravar em um banco de dados, baixar um arquivo ou navegar para uma aba. O manipulador não retorna um valor.
server <- function(input, output, session) {
observeEvent(input$save_btn, {
# Runs once each time save_btn is clicked
write.csv(current_data(), '/tmp/export.csv', row.names = FALSE)
showNotification('Saved!', type = 'message')
})
observeEvent(input$reset_btn, {
updateTextInput(session, 'search', value = '')
updateSliderInput(session, 'range', value = c(0, 100))
})
}eventReactive() — Valor sob demanda
eventReactive(eventExpr, valueExpr) é semelhante a reactive(), mas só recalcula quando um evento específico ocorre (por exemplo, um clique em um botão), e não sempre que suas dependências mudam. Use-o para executar cálculos dispendiosos somente quando o usuário fizer uma solicitação explícita.
server <- function(input, output, session) {
# Only re-run the model when 'Run Model' is clicked
model_result <- eventReactive(input$run_btn, {
# Expensive computation — only on button click
lm(as.formula(input$formula), data = get(input$dataset))
})
output$summary <- renderPrint({
summary(model_result())
})
}isolate() — Ler sem dependência
isolate({expr}) lê um valor ou uma expressão reativa sem estabelecer uma dependência reativa. O cálculo ao redor NÃO será executado novamente quando o valor isolado mudar. Use-o dentro de observe() ou observeEvent() para acessar o estado atual sem assinar alterações.
server <- function(input, output, session) {
observeEvent(input$add_row_btn, {
# Read current_data without depending on it
current <- isolate(data_rv())
new_row <- data.frame(
id = nrow(current) + 1,
value = input$new_value
)
data_rv(rbind(current, new_row))
})
}invalidateLater() — Atualização automática
invalidateLater(ms), dentro de um contexto reativo, agenda sua reexecução após ms milissegundos. Isso é usado para sondagem: atualizar um fluxo de dados ao vivo, atualizar um relógio ou verificar novas linhas no banco de dados em intervalos regulares.
server <- function(input, output, session) {
live_data <- reactive({
invalidateLater(5000) # re-run every 5 seconds
# Fetch fresh data from external source
httr2::request('https://api.example.com/stats') |>
httr2::req_perform() |>
httr2::resp_body_json()
})
output$live_plot <- renderPlot({
plot(live_data()$time, live_data()$value, type = 'l')
})
}reactlog — Depurar o grafo reativo
O pacote reactlog visualiza o grafo de dependências reativas. Ative-o antes de executar o aplicativo e chame reactlog_show() depois de interagir com ele para ver quais nós reativos foram invalidados e em que ordem. Ele é essencial para depurar aplicativos complexos.
library(reactlog)
# Enable reactlog BEFORE launching the app
reactlog_enable()
# Launch your app
shinyApp(ui, server)
# After interacting in the browser, in the R console:
shiny::reactlogShow()
# A viewer opens showing the reactive graph
# with timestamps and invalidation chainsAntipadrão do isolamento reativo
Um erro comum é ler acidentalmente um valor reativo dentro de um contexto não reativo ou criar dependências indesejadas ao ler um reativo dentro de um cálculo que deveria estar isolado. Seja sempre intencional quanto aos locais em que cria dependências e àqueles em que lê o estado como uma captura única.
server <- function(input, output, session) {
# WRONG: output depends on input$name, but also re-runs
# every time input$slider changes (unintended dependency)
output$msg <- renderText({
paste(input$name, 'total:', input$slider * 2)
})
# CORRECT: output only responds to input$name changes;
# slider is read as a snapshot
output$msg_correct <- renderText({
slider_val <- isolate(input$slider)
paste(input$name, 'snapshot total:', slider_val * 2)
})
}observe() versus observeEvent()
observe({...}) cria um observador reativo que é executado novamente automaticamente sempre que qualquer reativo que ele lê é alterado. observeEvent(event, {...}) é mais controlado: ele só é acionado por um evento específico. Prefira observeEvent() para efeitos colaterais acionados por botões, evitando reexecuções indesejadas.
server <- function(input, output, session) {
# observe: re-runs on ANY change in input$x or input$y
observe({
cat('x or y changed:', input$x, input$y, '\n')
})
# observeEvent: only runs when button is clicked
observeEvent(input$submit_btn, {
cat('Form submitted with x =', isolate(input$x), '\n')
}, ignoreNULL = TRUE, ignoreInit = TRUE)
}Verificação rápida
Qual é a principal diferença entre reactive({}) e eventReactive(event, {})?
Revisão da programação reativa
Principais aprendizados sobre o aprofundamento em programação reativa:
reactive({}): cálculo armazenado em cache, executado novamente quando as dependências mudam.reactiveVal(init): uma única variável reativa mutável; leia comval()e escreva comval(new).reactiveValues(...): lista nomeada de variáveis de estado reativas.observeEvent(event, {}): efeitos colaterais acionados por um evento específico.eventReactive(event, {}): valor calculado somente quando um evento específico ocorre.isolate({}): ler um reativo sem criar uma dependência.invalidateLater(ms): agendar reexecuções periódicas para atualizações ao vivo.- Use
reactlogpara visualizar e depurar o grafo de dependências reativas.
server <- function(input, output, session) {
# State
rv <- reactiveValues(data = NULL, n = 0)
# Load data on button click
observeEvent(input$load, {
rv$data <- read.csv(input$file$datapath)
rv$n <- nrow(rv$data)
})
# Expensive model only on 'Run' click
model <- eventReactive(input$run, {
lm(y ~ ., data = isolate(rv$data))
})
output$summary <- renderPrint({ summary(model()) })
}Perguntas Frequentes
A aula “Aprofundamento em programação reativa” é grátis?
Sim — o texto completo de “Aprofundamento em programação reativa” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de R Academy, atualize para CoddyKit PRO. O curso de R Academy inclui 4 aulas no total.
O que vou aprender em “Aprofundamento em programação reativa”?
Entenda valores reativos, reativos, observadores e o grafo reativo. Você pratica R Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar R Academy?
Nenhuma experiência prévia é necessária. R Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Aprofundamento em programação reativa”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de R Academy?
Sim. Cada aula de R Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Aprofundamento em programação reativa
- Módulos Shiny para reutilização de código
- Interface dinâmica com renderUI e insertUI
- Implantando aplicativos Shiny