0Pricing
R Academy · บทเรียน

เจาะลึกการเขียนโปรแกรมแบบรีแอกทีฟ

ทำความเข้าใจค่ารีแอกทีฟ ออบเซิร์ฟเวอร์ และกราฟรีแอกทีฟ

เจาะลึกการเขียนโปรแกรมแบบรีแอกทีฟ เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

การทำงานแบบรีแอกทีฟ: แนวคิดหลัก

โมเดล การเขียนโปรแกรมแบบรีแอกทีฟของ Shiny จะติดตามการขึ้นต่อกันระหว่างการคำนวณโดยอัตโนมัติ เมื่ออินพุตเปลี่ยนแปลง เฉพาะเอาต์พุตที่ขึ้นต่อกับอินพุตนั้นเท่านั้นที่จะทำงานใหม่ ไม่มีการทำงานเกินกว่านั้น การทำความเข้าใจกราฟการขึ้นต่อกันนี้เป็นกุญแจสำคัญในการเขียนแอป Shiny ที่มีประสิทธิภาพและปราศจากข้อผิดพลาด

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({}) — การคำนวณร่วมกัน

reactive({...}) สร้างนิพจน์แบบรีแอกทีฟที่มีการแคชและใช้ผลลัพธ์ร่วมกัน หากมีเอาต์พุตหลายรายการใช้การคำนวณราคาแพงเดียวกัน ให้ครอบการคำนวณนั้นด้วย reactive() เพื่อคำนวณครั้งเดียวต่อการเปลี่ยนแปลง แทนที่จะคำนวณครั้งเดียวต่อผู้ใช้ผลลัพธ์แต่ละรายการ เรียกใช้เหมือนฟังก์ชัน: 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() — ค่ารีแอกทีฟเดี่ยว

reactiveVal(initial_value) สร้างตัวแปรแบบรีแอกทีฟที่คุณสามารถอ่านและเขียนได้โดยใช้โปรแกรม อ่านค่าโดยเรียกใช้โดยไม่ส่งอาร์กิวเมนต์ และเขียนค่าโดยเรียกใช้พร้อมค่าใหม่ วิธีนี้เหมาะสำหรับจัดเก็บสถานะที่เปลี่ยนแปลงได้ ซึ่งมีผู้สังเกตการณ์หรือเอาต์พุตหลายรายการขึ้นต่ออยู่

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() — ตัวแปรสถานะหลายรายการ

reactiveValues(key = value, ...) คล้ายรายการที่มีชื่อ โดยแต่ละองค์ประกอบเป็นรีแอกทีฟ เมื่อองค์ประกอบใดเปลี่ยนแปลง เฉพาะเอาต์พุตที่อ่านองค์ประกอบนั้นจะถูกทำให้ใช้ไม่ได้ ใช้ฟังก์ชันนี้เพื่อจัดกลุ่มตัวแปรสถานะที่เกี่ยวข้องกันและมีการอัปเดตร่วมกัน

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() — ตอบสนองต่อเหตุการณ์

observeEvent(eventExpr, handlerExpr) จะเรียกใช้ handlerExpr ทุกครั้งที่ eventExpr เปลี่ยนแปลง ใช้สำหรับการทำงานข้างเคียง เช่น การอัปเดตสถานะ การเขียนลงฐานข้อมูล การดาวน์โหลดไฟล์ หรือการเปลี่ยนไปยังแท็บอื่น ฟังก์ชันจัดการจะไม่ส่งคืนค่า

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() — ค่าตามต้องการ

eventReactive(eventExpr, valueExpr) ทำงานคล้ายกับ reactive() แต่จะคำนวณใหม่เฉพาะเมื่อเกิดเหตุการณ์ที่ระบุ เช่น การคลิกปุ่ม ไม่ใช่ทุกครั้งที่สิ่งที่ขึ้นต่อกันเปลี่ยนแปลง ใช้สำหรับการคำนวณที่ใช้เวลานานและควรทำเมื่อผู้ใช้ร้องขออย่างชัดเจนเท่านั้น

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() — อ่านโดยไม่สร้างการขึ้นต่อกัน

isolate({expr}) อ่านค่ารีแอกทีฟหรือนิพจน์โดยไม่สร้างการขึ้นต่อกันแบบรีแอกทีฟ การคำนวณที่ครอบอยู่จะไม่ทำงานซ้ำเมื่อค่าที่แยกไว้นั้นเปลี่ยนแปลง ใช้ภายใน observe() หรือ observeEvent() เพื่อเข้าถึงสถานะปัจจุบันโดยไม่ติดตามการเปลี่ยนแปลง

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() — รีเฟรชอัตโนมัติ

การเรียก invalidateLater(ms) ภายในบริบทรีแอกทีฟจะกำหนดเวลาให้บริบทนั้นทำงานซ้ำหลังจากผ่านไป ms มิลลิวินาที ใช้สำหรับการตรวจสอบข้อมูลเป็นระยะ เช่น รีเฟรชแหล่งข้อมูลแบบสด อัปเดตนาฬิกา หรือตรวจสอบแถวใหม่ในฐานข้อมูลตามช่วงเวลาที่กำหนด

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 — ดีบักกราฟรีแอกทีฟ

แพ็กเกจ reactlog ใช้แสดงภาพกราฟการขึ้นต่อกันแบบรีแอกทีฟ ให้เปิดใช้ก่อนเรียกใช้แอป แล้วเรียก reactlog_show() หลังจากโต้ตอบกับแอป เพื่อดูว่าโหนดรีแอกทีฟใดถูกทำให้ใช้ไม่ได้และเกิดขึ้นตามลำดับใด เครื่องมือนี้จำเป็นสำหรับการดีบักแอปที่ซับซ้อน

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

รูปแบบต่อต้าน: การแยกรีแอกทีฟอย่างไม่เหมาะสม

ข้อผิดพลาดที่พบบ่อยคือการอ่านค่ารีแอกทีฟโดยไม่ตั้งใจภายในบริบทที่ไม่ใช่รีแอกทีฟ หรือการสร้างการขึ้นต่อกันที่ไม่ต้องการด้วยการอ่านค่ารีแอกทีฟภายในการคำนวณที่ควรแยกออกจากกัน ควรกำหนดให้ชัดเจนเสมอว่าจุดใดควรสร้างการขึ้นต่อกัน และจุดใดควรอ่านสถานะเป็นค่าภาพรวมเพียงครั้งเดียว

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() เทียบกับ observeEvent()

observe({...}) สร้างตัวสังเกตการณ์แบบรีแอกทีฟ ซึ่งจะทำงานซ้ำโดยอัตโนมัติเมื่อค่ารีแอกทีฟใด ๆ ที่ตัวสังเกตการณ์อ่านมีการเปลี่ยนแปลง ส่วน observeEvent(event, {...}) ควบคุมได้มากกว่า โดยจะทำงานเฉพาะเมื่อเกิดเหตุการณ์ที่ระบุ ควรเลือกใช้ observeEvent() สำหรับการทำงานข้างเคียงที่เกิดจากปุ่ม เพื่อหลีกเลี่ยงการทำงานซ้ำโดยไม่ตั้งใจ

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

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ความแตกต่างที่สำคัญระหว่าง reactive({}) และ eventReactive(event, {}) คืออะไร

ทบทวนการเขียนโปรแกรมแบบรีแอกทีฟ

ประเด็นสำคัญจากบทเจาะลึกการเขียนโปรแกรมแบบรีแอกทีฟ:

  • reactive({}): การคำนวณที่เก็บค่าไว้ในแคช และทำงานซ้ำเมื่อสิ่งที่ขึ้นต่อกันเปลี่ยนแปลง
  • reactiveVal(init): ตัวแปรรีแอกทีฟที่เปลี่ยนค่าได้หนึ่งตัว อ่านค่าด้วย val() และเขียนค่าด้วย val(new)
  • reactiveValues(...): รายการตัวแปรสถานะแบบรีแอกทีฟที่มีชื่อกำกับ
  • observeEvent(event, {}): การทำงานข้างเคียงที่ถูกเรียกใช้โดยเหตุการณ์ที่ระบุ
  • eventReactive(event, {}): ค่าที่คำนวณเฉพาะเมื่อเกิดเหตุการณ์ที่ระบุ
  • isolate({}): อ่านค่ารีแอกทีฟโดยไม่สร้างการขึ้นต่อกัน
  • invalidateLater(ms): กำหนดเวลาให้ทำงานซ้ำเป็นระยะเพื่ออัปเดตข้อมูลแบบสด
  • ใช้ reactlog เพื่อแสดงภาพและดีบักกราฟการขึ้นต่อกันแบบรีแอกทีฟ
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()) })
}

คำถามที่พบบ่อย

บทเรียน “เจาะลึกการเขียนโปรแกรมแบบรีแอกทีฟ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “เจาะลึกการเขียนโปรแกรมแบบรีแอกทีฟ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “เจาะลึกการเขียนโปรแกรมแบบรีแอกทีฟ”

ทำความเข้าใจค่ารีแอกทีฟ ออบเซิร์ฟเวอร์ และกราฟรีแอกทีฟ คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “เจาะลึกการเขียนโปรแกรมแบบรีแอกทีฟ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม

ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เจาะลึกการเขียนโปรแกรมแบบรีแอกทีฟ
  2. โมดูล Shiny เพื่อการนำโค้ดกลับมาใช้ใหม่
  3. ส่วนติดต่อผู้ใช้แบบไดนามิกด้วย renderUI และ insertUI
  4. การนำแอป Shiny ไปใช้งาน
← กลับไปที่ R Academy