0Pricing
R Academy · Aula

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 chains

Antipadrã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 com val() e escreva com val(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 reactlog para 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

  1. Aprofundamento em programação reativa
  2. Módulos Shiny para reutilização de código
  3. Interface dinâmica com renderUI e insertUI
  4. Implantando aplicativos Shiny
← Voltar para R Academy