Reaktive Programmierung im Detail
Verstehen Sie reaktive Werte, Reactives, Observer und den reaktiven Graphen
Reaktive Programmierung im Detail ist eine kostenlose R Academy-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des R Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der R Academy-Kurs umfasst insgesamt 4 Lektionen.
Reaktivität: Die Grundidee
Shinys Modell der reaktiven Programmierung verfolgt automatisch Abhängigkeiten zwischen Berechnungen. Wenn sich eine Eingabe ändert, werden nur die Ausgaben, die von ihr abhängen, erneut ausgeführt – und nichts weiter. Das Verständnis dieses Abhängigkeitsgraphen ist der Schlüssel zum Schreiben effizienter, fehlerfreier Shiny-Apps.
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({}) – Gemeinsame Berechnungen
reactive({...}) erstellt einen reaktiven Ausdruck, dessen Ergebnis zwischengespeichert und gemeinsam verwendet wird. Wenn mehrere Ausgaben dieselbe aufwendige Berechnung verwenden, kapseln Sie sie in reactive(), damit sie pro Änderung nur einmal statt einmal pro Verbraucher berechnet wird. Rufen Sie sie wie eine Funktion auf: 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() – Einzelner reaktiver Wert
reactiveVal(initial_value) erstellt eine reaktive Variable, die Sie programmgesteuert lesen und schreiben können. Lesen Sie sie auf, indem Sie sie ohne Argumente aufrufen, und schreiben Sie sie, indem Sie sie mit einem neuen Wert aufrufen. Dies ist nützlich, um veränderlichen Zustand zu speichern, von dem mehrere Observer oder Ausgaben abhängen.
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() – Mehrere Zustandsvariablen
reactiveValues(key = value, ...) ähnelt einer benannten Liste, deren jedes Element reaktiv ist. Wenn sich ein Element ändert, werden nur die Ausgaben, die dieses Element lesen, invalidiert. Verwenden Sie dies, um zusammengehörige Zustandsvariablen zu gruppieren, die gemeinsam aktualisiert werden.
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() – Auf Ereignisse reagieren
observeEvent(eventExpr, handlerExpr) führt handlerExpr jedes Mal aus, wenn sich eventExpr ändert. Es wird für Seiteneffekte verwendet, etwa zum Aktualisieren des Zustands, Schreiben in eine Datenbank, Herunterladen einer Datei oder Navigieren zu einem Tab. Der Handler gibt keinen Wert zurück.
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() — Wert auf Abruf
eventReactive(eventExpr, valueExpr) funktioniert ähnlich wie reactive(), wird aber nur neu berechnet, wenn ein bestimmtes Ereignis ausgelöst wird, beispielsweise ein Button-Klick, und nicht bei jeder Änderung seiner Abhängigkeiten. Verwenden Sie es, um aufwendige Berechnungen nur auf ausdrückliche Anforderung der Benutzerin oder des Benutzers auszuführen.
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() — Lesen ohne Abhängigkeit
isolate({expr}) liest einen reaktiven Wert oder Ausdruck, ohne eine reaktive Abhängigkeit herzustellen. Die umgebende Berechnung wird NICHT erneut ausgeführt, wenn sich der isolierte Wert ändert. Verwenden Sie es innerhalb von observe() oder observeEvent(), um auf den aktuellen Zustand zuzugreifen, ohne Änderungen zu abonnieren.
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() — Automatische Aktualisierung
invalidateLater(ms) innerhalb eines reaktiven Kontexts plant dessen erneute Ausführung nach ms Millisekunden. Dies wird für Polling verwendet, etwa zum Aktualisieren eines Live-Datenstroms, einer Uhr oder zum regelmäßigen Prüfen auf neue Datenbankzeilen.
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 — Reaktiven Graphen debuggen
Das Paket reactlog visualisiert den reaktiven Abhängigkeitsgraphen. Aktivieren Sie es vor dem Ausführen der App und rufen Sie nach Interaktionen reactlog_show() auf, um zu sehen, welche reaktiven Knoten ungültig wurden und in welcher Reihenfolge. Das ist für das Debuggen komplexer Apps unverzichtbar.
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: reaktive Isolation
Ein häufiger Fehler besteht darin, versehentlich einen reaktiven Wert in einem nicht reaktiven Kontext zu lesen oder unerwünschte Abhängigkeiten zu erzeugen, indem ein reaktiver Wert innerhalb einer Berechnung gelesen wird, die isoliert sein sollte. Legen Sie immer bewusst fest, wo Sie Abhängigkeiten erzeugen und wo Sie den Zustand nur einmalig als Momentaufnahme lesen.
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() im Vergleich zu observeEvent()
observe({...}) erstellt einen reaktiven Observer, der automatisch erneut ausgeführt wird, sobald sich ein gelesener reaktiver Wert ändert. observeEvent(event, {...}) ist kontrollierter: Es wird nur durch ein bestimmtes Ereignis ausgelöst. Bevorzugen Sie observeEvent() für durch Buttons ausgelöste Seiteneffekte, um unbeabsichtigte erneute Ausführungen zu vermeiden.
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)
}Kurztest
Was ist der wesentliche Unterschied zwischen reactive({}) und eventReactive(event, {})?
Rückblick auf reaktive Programmierung
Die wichtigsten Erkenntnisse aus „Reactive Programming Deep Dive“:
reactive({}): zwischengespeicherte Berechnung, die bei Änderungen der Abhängigkeiten erneut ausgeführt wird.reactiveVal(init): einzelne veränderbare reaktive Variable; Lesen mitval(), Schreiben mitval(new).reactiveValues(...): benannte Liste reaktiver Zustandsvariablen.observeEvent(event, {}): durch ein bestimmtes Ereignis ausgelöste Seiteneffekte.eventReactive(event, {}): Wert, der nur berechnet wird, wenn ein bestimmtes Ereignis ausgelöst wird.isolate({}): einen reaktiven Wert lesen, ohne eine Abhängigkeit zu erzeugen.invalidateLater(ms): regelmäßige erneute Ausführung für Live-Aktualisierungen planen.- Verwenden Sie
reactlog, um den reaktiven Abhängigkeitsgraphen zu visualisieren und zu debuggen.
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()) })
}Häufig gestellte Fragen
Ist die Lektion „Reaktive Programmierung im Detail“ kostenlos?
Ja — der vollständige Text von „Reaktive Programmierung im Detail“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des R Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der R Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Reaktive Programmierung im Detail“?
Verstehen Sie reaktive Werte, Reactives, Observer und den reaktiven Graphen Du übst R Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um R Academy zu starten?
Keine Vorkenntnisse erforderlich. R Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „Reaktive Programmierung im Detail“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser R Academy-Lektion Code schreiben und ausführen?
Ja. Jede R Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Reaktive Programmierung im Detail
- Shiny-Module zur Codewiederverwendung
- Dynamische UI mit renderUI und insertUI
- Shiny-Apps bereitstellen