Approfondimento della programmazione reattiva
Comprenda i valori reattivi, i reactive, gli observer e il grafo reattivo
Approfondimento della programmazione reattiva è una lezione R Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento R Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso R Academy include 4 lezioni in totale.
Reattività: l'idea fondamentale
Il modello di programmazione reattiva di Shiny tiene traccia automaticamente delle dipendenze tra i calcoli. Quando cambia un input, vengono rieseguiti solo gli output che dipendono da esso, e nient'altro. Comprendere questo grafo delle dipendenze è fondamentale per scrivere app Shiny efficienti e prive di bug.
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({}) — Calcoli condivisi
reactive({...}) crea un'espressione reattiva il cui risultato viene memorizzato nella cache e condiviso. Se più output utilizzano lo stesso calcolo costoso, lo racchiuda in reactive() per eseguirlo una sola volta a ogni modifica, anziché una volta per ogni utilizzatore. La richiami come una funzione: 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() — Valore reattivo singolo
reactiveVal(initial_value) crea una variabile reattiva che può leggere e modificare programmaticamente. La legga chiamandola senza argomenti; la modifichi chiamandola con un nuovo valore. È utile per memorizzare uno stato mutabile da cui dipendono più observer o output.
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() — Più variabili di stato
reactiveValues(key = value, ...) è simile a una lista denominata in cui ogni elemento è reattivo. Quando cambia un elemento, vengono invalidati solo gli output che leggono quell'elemento. Lo utilizzi per raggruppare variabili di stato correlate che vengono aggiornate insieme.
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() — Rispondere agli eventi
observeEvent(eventExpr, handlerExpr) esegue handlerExpr ogni volta che eventExpr cambia. Viene usato per gli effetti collaterali: aggiornare lo stato, scrivere in un database, scaricare un file o passare a una scheda. Il gestore non restituisce alcun valore.
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() — Valore su richiesta
eventReactive(eventExpr, valueExpr) è simile a reactive(), ma ricalcola il valore solo quando si verifica un evento specifico, ad esempio il clic su un pulsante, e non ogni volta che cambiano le dipendenze. Lo utilizzi per eseguire calcoli costosi solo su esplicita richiesta dell'utente.
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() — Lettura senza dipendenze
isolate({expr}) legge un valore o un'espressione reattiva senza stabilire una dipendenza reattiva. Il calcolo circostante NON verrà eseguito di nuovo quando cambia il valore isolato. Lo utilizzi all'interno di observe() o observeEvent() per accedere allo stato corrente senza sottoscriversi alle modifiche.
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() — Aggiornamento automatico
invalidateLater(ms), all'interno di un contesto reattivo, ne pianifica la nuova esecuzione dopo ms millisecondi. Viene usato per il polling: aggiornare un flusso di dati in tempo reale, aggiornare un orologio o verificare a intervalli regolari la presenza di nuove righe nel database.
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 — Debug del grafo reattivo
Il pacchetto reactlog visualizza il grafo delle dipendenze reattive. Lo abiliti prima di eseguire l'app e chiami reactlog_show() dopo aver interagito con essa, per vedere quali nodi reattivi sono stati invalidati e in quale ordine. È essenziale per eseguire il debug di app complesse.
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 chainsAnti-pattern dell'isolamento reattivo
Un errore comune consiste nel leggere accidentalmente un valore reattivo all'interno di un contesto non reattivo, oppure nel creare dipendenze indesiderate leggendo un valore reattivo all'interno di un calcolo che dovrebbe essere isolato. Presti sempre attenzione a dove crea le dipendenze e a dove legge lo stato come istantanea una tantum.
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() e observeEvent()
observe({...}) crea un osservatore reattivo che viene rieseguito automaticamente ogni volta che cambia un valore reattivo letto. observeEvent(event, {...}) offre un controllo maggiore: si attiva solo in risposta a un evento specifico. Preferisca observeEvent() per gli effetti collaterali attivati dai pulsanti, così da evitare riesecuzioni indesiderate.
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 rapida
Qual è la differenza fondamentale tra reactive({}) e eventReactive(event, {})?
Riepilogo della programmazione reattiva
Punti chiave dell'approfondimento sulla programmazione reattiva:
reactive({}): calcolo memorizzato nella cache, rieseguito quando cambiano le dipendenze.reactiveVal(init): singola variabile reattiva modificabile; lettura conval(), scrittura conval(new).reactiveValues(...): elenco denominato di variabili di stato reattive.observeEvent(event, {}): effetti collaterali attivati da un evento specifico.eventReactive(event, {}): valore calcolato solo quando si verifica un evento specifico.isolate({}): lettura di un valore reattivo senza creare una dipendenza.invalidateLater(ms): pianificazione di riesecuzioni periodiche per aggiornamenti in tempo reale.- Utilizzi
reactlogper visualizzare ed eseguire il debug del grafo delle dipendenze reattive.
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()) })
}Domande Frequenti
La lezione «Approfondimento della programmazione reattiva» è gratuita?
Sì — il testo completo di «Approfondimento della programmazione reattiva» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso R Academy, passa a CoddyKit PRO. Il corso R Academy include 4 lezioni in totale.
Cosa imparerò in «Approfondimento della programmazione reattiva»?
Comprenda i valori reattivi, i reactive, gli observer e il grafo reattivo Eserciti R Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare R Academy?
Non è richiesta alcuna esperienza precedente. R Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Approfondimento della programmazione reattiva»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione R Academy?
Sì. Ogni lezione R Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Approfondimento della programmazione reattiva
- Moduli Shiny per riutilizzare il codice
- Interfaccia dinamica con renderUI e insertUI
- Distribuzione delle app Shiny