0Pricing
R Academy · 강의

반응형 프로그래밍 심화

반응형 값, 반응형 객체, 관찰자 및 반응형 그래프를 이해합니다.

반응형 프로그래밍 심화은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 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)는 eventExpr가 변경될 때마다 handlerExpr를 실행합니다. 상태 업데이트, 데이터베이스에 기록, 파일 다운로드, 탭 이동과 같은 부수 효과에 사용합니다. 핸들러는 값을 반환하지 않습니다.

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

자주 묻는 질문

“반응형 프로그래밍 심화” 강의는 무료인가요?

네 — “반응형 프로그래밍 심화” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“반응형 프로그래밍 심화”에서 뭘 배우나요?

반응형 값, 반응형 객체, 관찰자 및 반응형 그래프를 이해합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

R Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 R Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“반응형 프로그래밍 심화” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 R Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 R Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 반응형 프로그래밍 심화
  2. 코드 재사용을 위한 Shiny 모듈
  3. renderUI와 insertUI를 활용한 동적 UI
  4. Shiny 앱 배포
← R Academy(으)로 돌아가기