0Pricing
R Academy · Lección

Profundización en la programación reactiva

Comprenda los valores reactivos, las expresiones reactivas, los observadores y el grafo reactivo.

Profundización en la programación reactiva es una lección gratuita de R Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de R Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de R Academy incluye 4 lecciones en total.

Reactividad: la idea fundamental

El modelo de programación reactiva de Shiny realiza un seguimiento automático de las dependencias entre cálculos. Cuando cambia una entrada, solo se vuelven a ejecutar las salidas que dependen de ella, y nada más. Comprender este grafo de dependencias es fundamental para escribir aplicaciones Shiny eficientes y sin errores.

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 compartidos

reactive({...}) crea una expresión reactiva cuyo resultado se almacena en caché y se comparte. Si varias salidas utilizan el mismo cálculo costoso, inclúyalo en reactive() para calcularlo una vez por cambio, en lugar de una vez por consumidor. Llámelo como una función: 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() — Valor reactivo único

reactiveVal(initial_value) crea una variable reactiva que puede leer y escribir mediante programación. Léala llamándola sin argumentos y escríbala llamándola con un valor nuevo. Resulta útil para almacenar un estado mutable del que dependan varios observadores o salidas.

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() — Varias variables de estado

reactiveValues(key = value, ...) funciona como una lista con nombre cuyos elementos son reactivos. Cuando cambia cualquier elemento, solo se invalidan las salidas que leen ese elemento. Úselo para agrupar variables de estado relacionadas que se actualizan conjuntamente.

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() — Responder a eventos

observeEvent(eventExpr, handlerExpr) ejecuta handlerExpr cada vez que cambia eventExpr. Se utiliza para efectos secundarios: actualizar el estado, escribir en una base de datos, descargar un archivo o navegar a una pestaña. El controlador no devuelve ningún 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 bajo demanda

eventReactive(eventExpr, valueExpr) es como reactive(), pero solo vuelve a calcularse cuando se produce un evento específico (por ejemplo, al hacer clic en un botón), no cada vez que cambian sus dependencias. Úselo para ejecutar cálculos costosos únicamente cuando el usuario lo solicite explícitamente.

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() — Leer sin dependencia

isolate({expr}) lee un valor o una expresión reactiva sin establecer una dependencia reactiva. El cálculo que la contiene NO volverá a ejecutarse cuando cambie el valor aislado. Úselo dentro de observe() o observeEvent() para acceder al estado actual sin suscribirse a los cambios.

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() — Actualización automática

invalidateLater(ms), dentro de un contexto reactivo, programa su reejecución después de ms milisegundos. Se utiliza para realizar consultas periódicas: actualizar un flujo de datos en directo, actualizar un reloj o comprobar si hay nuevas filas en una base de datos a 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 el grafo reactivo

El paquete reactlog visualiza el grafo de dependencias reactivas. Actívelo antes de ejecutar la aplicación y llame a reactlog_show() después de interactuar con ella para ver qué nodos reactivos se invalidaron y en qué orden. Es esencial para depurar aplicaciones complejas.

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

Antipatrón: aislamiento reactivo

Un error común consiste en leer accidentalmente un valor reactivo dentro de un contexto no reactivo, o crear dependencias no deseadas al leer un valor reactivo dentro de un cálculo que debería estar aislado. Sea siempre intencional sobre dónde crea dependencias y dónde lee el estado como una instantánea puntual.

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() frente a observeEvent()

observe({...}) crea un observador reactivo que se vuelve a ejecutar automáticamente cada vez que cambia cualquier valor reactivo que lee. observeEvent(event, {...}) ofrece un mayor control: solo se activa ante un evento específico. Prefiera observeEvent() para los efectos secundarios activados por botones y evite así ejecuciones no deseadas.

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)
}

Comprobación rápida

¿Cuál es la diferencia principal entre reactive({}) y eventReactive(event, {})?

Repaso de la programación reactiva

Conceptos clave de Inmersión profunda en la programación reactiva:

  • reactive({}): cálculo almacenado en caché que se vuelve a ejecutar cuando cambian sus dependencias.
  • reactiveVal(init): única variable reactiva mutable; se lee con val() y se escribe con val(new).
  • reactiveValues(...): lista con nombre de variables de estado reactivas.
  • observeEvent(event, {}): efectos secundarios activados por un evento específico.
  • eventReactive(event, {}): valor que se calcula únicamente cuando se produce un evento específico.
  • isolate({}): leer un valor reactivo sin crear una dependencia.
  • invalidateLater(ms): programar ejecuciones periódicas para realizar actualizaciones en directo.
  • Use reactlog para visualizar y depurar el grafo de dependencias reactivas.
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()) })
}

Preguntas frecuentes

¿La lección «Profundización en la programación reactiva» es gratis?

Sí — el texto completo de «Profundización en la programación reactiva» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de R Academy, actualiza a CoddyKit PRO. El curso de R Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Profundización en la programación reactiva»?

Comprenda los valores reactivos, las expresiones reactivas, los observadores y el grafo reactivo. Practicas R Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar R Academy?

No se requiere experiencia previa. R Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «Profundización en la programación reactiva»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de R Academy?

Sí. Cada lección de R Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Profundización en la programación reactiva
  2. Módulos de Shiny para reutilizar código
  3. Interfaz de usuario dinámica con renderUI e insertUI
  4. Implementación de aplicaciones Shiny
← Volver a R Academy