이 교재에서 다룬 내용을 한 장으로 모았습니다. 앱을 만들다가 막힐 때 여기를 먼저 펼쳐보세요.
모든 Shiny 앱은 UI와 Server, 두 부분으로 이루어집니다.
# Shiny 앱의 기본 뼈대
library(shiny)
ui <- fluidPage(
# 화면 레이아웃과 위젯 정의
)
server <- function(input, output, session) {
# 반응형 로직과 출력 정의
}
shinyApp(ui, server)
| 함수 |
역할 |
page_fluid() |
반응형 유동 레이아웃 (bslib) |
page_sidebar() |
사이드바 + 메인 레이아웃 (bslib) |
page_navbar() |
상단 네비게이션 바 (bslib) |
layout_columns() |
컬럼 기반 배치 (bslib) |
card() |
컨텐츠 카드 박스 (bslib) |
navset_card_tab() |
탭 패널 (bslib) |
sidebar() |
사이드바 정의 (bslib) |
| 함수 |
입력 유형 |
반환값 |
textInput() |
텍스트 |
character |
numericInput() |
숫자 |
numeric |
sliderInput() |
슬라이더 |
numeric 또는 c(min, max) |
selectInput() |
드롭다운 |
character |
radioButtons() |
라디오 버튼 |
character |
checkboxGroupInput() |
체크박스 |
character vector |
dateRangeInput() |
날짜 범위 |
c(Date, Date) |
fileInput() |
파일 업로드 |
data.frame (name, size, type, datapath) |
actionButton() |
버튼 |
integer (클릭 횟수) |
| Server 함수 |
UI 함수 |
출력 내용 |
renderText() |
textOutput() |
텍스트 |
renderPrint() |
verbatimTextOutput() |
콘솔 출력 |
renderPlot() |
plotOutput() |
ggplot2 차트 |
renderPlotly() |
plotlyOutput() |
인터랙티브 차트 |
renderTable() |
tableOutput() |
기본 테이블 |
renderDT() |
DTOutput() |
인터랙티브 테이블 |
renderUI() |
uiOutput() |
동적 UI |
renderLeaflet() |
leafletOutput() |
지도 |
downloadHandler() |
downloadButton() |
파일 다운로드 |
| 함수 |
역할 |
특징 |
reactive() |
반응형 표현식 |
여러 출력에서 공유 가능 |
reactiveVal() |
단일 반응형 값 |
val(), val(새값) 사용 |
reactiveValues() |
반응형 리스트 |
rv$x, rv$x <- 새값 사용 |
observe() |
반응형 부작용 |
값 반환 없음, 항상 실행 |
observeEvent() |
이벤트 기반 실행 |
특정 입력 변화에만 반응 |
eventReactive() |
이벤트 기반 반응식 |
버튼 클릭 등 명시적 트리거 |
isolate() |
반응성 격리 |
읽기는 하되 의존성 미등록 |
req() |
실행 조건 검사 |
NULL·NA 등일 때 실행 중단 |
invalidateLater() |
타이머 무효화 |
자동 갱신에 사용 |
reactivePoll() |
폴링 반응식 |
변경 감지 후 데이터 읽기 |
reactiveFileReader() |
파일 모니터링 |
파일 변경 시 자동 재읽기 |
# 모듈 UI
myModuleUI <- function(id) {
ns <- NS(id)
tagList(
selectInput(ns("var"), "선택", choices = letters)
)
}
# 모듈 Server
myModuleServer <- function(id) {
moduleServer(id, function(input, output, session) {
reactive({ input$var }) # 반응형 반환
})
}
# 사용
ui <- page_fluid(myModuleUI("mod1"), myModuleUI("mod2"))
server <- function(input, output, session) {
val1 <- myModuleServer("mod1")
val2 <- myModuleServer("mod2")
}
1. 데이터 준비 — global.R, parquet 변환, 사전 집계
2. UI 스케치 — 손으로 그려보기, layout_columns 배치
3. 하드코딩 출력 — reactive 없이 정적 데이터로 차트 먼저 완성
4. 반응형 연결 — input → reactive → render 연결
5. 모듈 추출 — 반복되는 패턴 발견 시 모듈로 분리
6. 성능 최적화 — bindCache, memoise 적용
7. 테스트 — shinytest2로 핵심 경로 자동화
8. 배포 — shinyapps.io 또는 Docker
3번 "하드코딩 출력"이 중요합니다. 반응형을 너무 일찍 넣으면 UI 버그와 로직 버그가 섞여서 디버깅이 어려워집니다. 차트와 테이블이 정적 데이터로 잘 보이는 것을 먼저 확인한 다음 반응형을 붙이세요.
# 1. 반응형 값 콘솔 출력
observe({ message("input$region: ", paste(input$region, collapse = ", ")) })
# 2. 브라우저 일시정지
server <- function(input, output, session) {
browser() # R 인터랙티브 디버거 진입
...
}
# 3. reactive 값 UI에 표시
output$debug <- renderPrint({ reactiveValuesToList(input) })
# ui에: verbatimTextOutput("debug")
# 4. 오류 메시지 상세화
options(shiny.error = browser)
options(shiny.trace = TRUE)