Fordybelse i reaktiv programmering
Forstå reactive values, reactives, observers og den reaktive graf.
Fordybelse i reaktiv programmering er en gratis R Academy-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i R Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. R Academy-kurset indeholder 4 lektioner i alt.
Reaktivitet: den grundlæggende idé
Shinys model for reaktiv programmering holder automatisk styr på afhængigheder mellem beregninger. Når et input ændres, udføres kun de outputs, der afhænger af det, igen — ikke mere. Forståelse af denne afhængighedsgraf er nøglen til at skrive effektive og fejlfri 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({}) — Delte beregninger
reactive({...}) opretter et reaktivt udtryk, hvis resultat cachelagres og deles. Hvis flere outputs bruger den samme beregningstunge beregning, skal du pakke den ind i reactive(), så den beregnes én gang pr. ændring i stedet for én gang pr. forbruger. Kald den som en funktion: 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() — En enkelt reaktiv værdi
reactiveVal(initial_value) opretter en reaktiv variabel, som du kan læse og skrive programmatisk. Læs den ved at kalde den uden argumenter, og skriv til den ved at kalde den med en ny værdi. Det er nyttigt til lagring af tilstand, der kan ændres, og som flere observatører eller outputs afhænger af.
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() — Flere tilstandsvariabler
reactiveValues(key = value, ...) fungerer som en navngivet liste, hvor hvert element er reaktivt. Når et element ændres, bliver kun de outputs, der læser dette element, ugyldige. Brug den til at gruppere relaterede tilstandsvariabler, der opdateres sammen.
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() — Reaktion på hændelser
observeEvent(eventExpr, handlerExpr) kører handlerExpr, hver gang eventExpr ændres. Den bruges til bivirkninger: opdatering af tilstand, skrivning til en database, download af en fil eller navigation til en fane. Handleren returnerer ikke en værdi.
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() — Værdi efter behov
eventReactive(eventExpr, valueExpr) fungerer ligesom reactive(), men genberegner kun, når en bestemt hændelse udløses (f.eks. et knapklik), ikke hver gang dens afhængigheder ændres. Brug den til kun at køre beregningstunge beregninger efter en udtrykkelig anmodning fra brugeren.
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() — Læsning uden afhængighed
isolate({expr}) læser en reaktiv værdi eller et reaktivt udtryk uden at oprette en reaktiv afhængighed. Den omgivende beregning køres IKKE igen, når den isolerede værdi ændres. Brug den i observe() eller observeEvent() for at få adgang til den aktuelle tilstand uden at abonnere på ændringer.
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() — Automatisk opdatering
invalidateLater(ms) i en reaktiv kontekst planlægger, at den køres igen efter ms millisekunder. Det bruges til polling: opdatering af et live-datafeed, opdatering af et ur eller kontrol af nye rækker i en database med faste intervaller.
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 — Fejlfinding af den reaktive graf
Pakken reactlog visualiserer grafen over reaktive afhængigheder. Aktivér den, før du kører appen, og kald reactlog_show(), efter du har interageret med appen, for at se, hvilke reaktive noder der blev ugyldige, og i hvilken rækkefølge. Den er afgørende ved fejlfinding af komplekse apps.
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-mønsteret reaktiv isolering
En almindelig fejl er ved et uheld at læse en reaktiv værdi i en ikke-reaktiv kontekst eller at oprette uønskede afhængigheder ved at læse en reaktiv værdi i en beregning, der burde være isoleret. Vær altid bevidst om, hvor du opretter afhængigheder, og hvor du læser tilstanden som et øjebliksbillede.
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() vs observeEvent()
observe({...}) opretter en reaktiv observatør, der automatisk køres igen, når en reaktiv værdi, som den læser, ændres. observeEvent(event, {...}) er mere kontrolleret: Den udløses kun af en bestemt hændelse. Foretræk observeEvent() til bivirkninger, der styres af knapper, så utilsigtet genkørsel undgås.
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)
}Hurtigt tjek
Hvad er den vigtigste forskel på reactive({}) og eventReactive(event, {})?
Opsummering af reaktiv programmering
Vigtigste pointer fra det dybdegående modul om reaktiv programmering:
reactive({}): cachet beregning, der køres igen, når afhængigheder ændres.reactiveVal(init): enkelt muterbart reaktivt variabel; læs medval(), skriv medval(new).reactiveValues(...): navngivet liste med reaktive tilstandsvariable.observeEvent(event, {}): bivirkninger, der udløses af en bestemt hændelse.eventReactive(event, {}): værdi, der kun beregnes, når en bestemt hændelse udløses.isolate({}): læsning af en reaktiv værdi uden at oprette en afhængighed.invalidateLater(ms): planlægning af periodisk genkørsel til live-opdateringer.- Brug
reactlogtil at visualisere og fejlfinde grafen over reaktive afhængigheder.
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()) })
}Lær R med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 43
- Lektioner
- 159
Ofte stillede spørgsmål
Er lektionen “Fordybelse i reaktiv programmering” gratis?
Ja — alle 3 lektioner i læringssporet R Academy, inklusive “Fordybelse i reaktiv programmering”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. R Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Fordybelse i reaktiv programmering”?
Forstå reactive values, reactives, observers og den reaktive graf. Du øver dig i R Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på R Academy?
Der kræves ingen tidligere erfaring. R Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.
Hvor lang tid tager lektionen “Fordybelse i reaktiv programmering”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne R Academy-lektion?
Ja. Alle R Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Fordybelse i reaktiv programmering
- Shiny-moduler til genbrug af kode
- Dynamisk UI med renderUI og insertUI
- Udrulning af Shiny-apps