renderUI와 insertUI를 활용한 동적 UI
사용자 입력과 서버 상태에 따라 UI 요소를 즉시 생성합니다.
renderUI와 insertUI를 활용한 동적 UI은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 R Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
동적 UI — 이유와 시점
때로는 앱 시작 시 필요한 UI를 완전히 결정할 수 없습니다. UI가 사용자의 선택, 로드된 데이터 또는 실행 중 조건에 따라 달라지기 때문입니다. Shiny는 두 가지 방법을 제공합니다. renderUI()는 자리 표시자의 전체 내용을 교체하고, insertUI()/removeUI()는 모든 내용을 교체하지 않고 요소를 추가하거나 제거합니다.
library(shiny)
# Static UI: columns always shown
# ui <- fluidPage(selectInput('x', ...), selectInput('y', ...))
# Dynamic UI: columns depend on which dataset was loaded
# ui <- fluidPage(fileInput('upload', ...), uiOutput('var_selectors'))renderUI()와 uiOutput()
서버에서 renderUI({...})는 UI 요소를 반응형으로 만들어 반환합니다. UI에서 uiOutput('id')는 renderUI가 생성하는 내용을 표시하는 자리 표시자를 만듭니다. 반응형 코드가 다시 실행될 때마다 자리 표시자의 전체 내용이 교체됩니다.
ui <- fluidPage(
selectInput('dataset', 'Dataset:', choices = c('iris', 'mtcars')),
uiOutput('column_selector') # placeholder
)
server <- function(input, output, session) {
output$column_selector <- renderUI({
df <- get(input$dataset) # reactive dependency on dataset
selectInput('col', 'Choose Column:',
choices = names(df))
})
}
shinyApp(ui, server)여러 컨트롤과 함께 renderUI() 사용하기
한 번에 여러 UI 요소를 렌더링하려면 renderUI()에서 tagList()를 반환하십시오. 컨트롤 수가 데이터에 따라 달라질 때 사용하는 표준 패턴입니다. 예를 들어 데이터셋의 각 열마다 필터 하나를 생성할 수 있습니다.
server <- function(input, output, session) {
output$filters <- renderUI({
df <- get(input$dataset)
nums <- names(df)[sapply(df, is.numeric)]
# One slider per numeric column
sliders <- lapply(nums, function(col) {
rng <- range(df[[col]], na.rm = TRUE)
sliderInput(
inputId = paste0('filter_', col),
label = col,
min = rng[1], max = rng[2],
value = rng
)
})
tagList(sliders) # render all sliders
})
}insertUI() — 요소를 동적으로 추가하기
insertUI(selector, where, ui)는 전체 페이지를 다시 만들지 않고 DOM에 UI 요소를 삽입합니다. 삽입 위치를 지정하려면 CSS 선택자를 사용하십시오. where에는 'afterEnd', 'beforeEnd', 'afterBegin' 또는 'beforeBegin'을 사용할 수 있습니다.
server <- function(input, output, session) {
item_count <- reactiveVal(0)
observeEvent(input$add_item, {
item_count(item_count() + 1)
id <- paste0('item_', item_count())
insertUI(
selector = '#item_container', # CSS selector
where = 'beforeEnd',
ui = div(
id = id,
style = 'padding: 5px; border: 1px solid #ccc; margin: 3px;',
textInput(id, paste('Item', item_count()), value = '')
)
)
})
}removeUI() — 요소 삭제하기
removeUI(selector)는 CSS 선택자와 일치하는 첫 번째 DOM 요소를 제거합니다. 일치하는 모든 요소를 제거하려면 multiple = TRUE를 사용하십시오. 사용자가 항목을 추가하고 제거할 수 있는 목록 기반 UI에서 insertUI()와 함께 사용합니다.
server <- function(input, output, session) {
observeEvent(input$remove_last, {
# Remove the last item div
n <- isolate(item_count())
if (n > 0) {
removeUI(selector = paste0('#item_', n))
item_count(n - 1)
}
})
observeEvent(input$clear_all, {
# Remove all items matching a class
removeUI(selector = '.dynamic-item', multiple = TRUE)
item_count(0)
})
}conditionalPanel() — 클라이언트 측 표시 여부
conditionalPanel(condition, ...)은 브라우저에서 평가되는 JavaScript 조건에 따라 UI 요소를 표시하거나 숨깁니다. renderUI()와 달리 요소는 항상 DOM에 존재하며 표시되거나 숨겨지기만 합니다. 서버와 통신할 필요가 없으므로 간단한 표시 여부 로직에서는 더 빠릅니다.
ui <- fluidPage(
selectInput('plot_type', 'Plot Type:',
choices = c('scatter', 'histogram', 'boxplot')),
# Only shown when scatter is selected
conditionalPanel(
condition = "input.plot_type == 'scatter'",
selectInput('x_var', 'X Variable:', choices = names(mtcars)),
selectInput('y_var', 'Y Variable:', choices = names(mtcars))
),
# Only shown when histogram is selected
conditionalPanel(
condition = "input.plot_type == 'histogram'",
sliderInput('bins', 'Number of bins:', 5, 50, 20)
),
plotOutput('main_plot')
)updateSelectInput() — 기존 입력 수정하기
전체 입력 컨트롤을 교체하는 대신 updateSelectInput(session, id, choices, selected)를 사용하여 기존 selectInput의 선택 항목이나 선택된 값만 업데이트할 수 있습니다. 모든 입력 유형에 updateSliderInput(), updateTextInput() 등과 같은 유사한 업데이트 함수가 있습니다.
server <- function(input, output, session) {
# When dataset changes, update the column selector
observeEvent(input$dataset, {
df <- get(input$dataset)
updateSelectInput(
session = session,
inputId = 'column',
choices = names(df),
selected = names(df)[1]
)
})
# Reset slider when reset button pressed
observeEvent(input$reset_btn, {
updateSliderInput(session, 'n_items',
value = 20, min = 1, max = 100)
})
}updateSliderInput()와 updateNumericInput()
업데이트 함수는 브라우저에 메시지를 보내 기존 입력의 현재 값, 최솟값, 최댓값 또는 레이블을 수정합니다. renderUI()로 컨트롤을 삭제하고 다시 만드는 것보다 효율적이며, 페이지 레이아웃에서 컨트롤의 위치도 유지합니다.
server <- function(input, output, session) {
# When data loads, set slider max to actual data length
observeEvent(input$load_data, {
data <- readRDS(input$upload$datapath)
updateSliderInput(session, 'row_slider',
min = 1,
max = nrow(data),
value = c(1, min(50, nrow(data)))
)
updateNumericInput(session, 'page_size',
max = nrow(data),
value = min(10, nrow(data))
)
})
}req()로 renderUI 입력에 액세스하기
renderUI()로 동적으로 생성된 입력은 렌더링될 때까지 NULL입니다. 동적으로 생성된 입력에 의존하는 모든 서버 코드에서 req(input$dynamic_input)을 사용하여 초기화 중 오류가 발생하지 않도록 하십시오.
server <- function(input, output, session) {
# dynamic input: 'col' is created by renderUI
output$column_selector <- renderUI({
selectInput('col', 'Column:', choices = names(get(input$dataset)))
})
output$summary_stats <- renderPrint({
req(input$col) # wait until 'col' exists
req(input$dataset) # and dataset is chosen
df <- get(input$dataset)
summary(df[[input$col]])
})
}appendTab()으로 동적 탭 만들기
appendTab(inputId, tab, select)은 실행 중에 tabsetPanel()에 새 탭을 추가합니다. removeTab(inputId, target)은 탭 하나를 제거합니다. 이 패턴을 사용하면 사용자가 동적으로 생성된 분석 화면을 열고 닫고 전환할 수 있는 작업 흐름을 만들 수 있습니다.
ui <- fluidPage(
actionButton('add_tab', 'Open New Analysis Tab'),
tabsetPanel(id = 'analysis_tabs', type = 'tabs')
)
server <- function(input, output, session) {
tab_count <- reactiveVal(0)
observeEvent(input$add_tab, {
tab_count(tab_count() + 1)
n <- tab_count()
appendTab(
inputId = 'analysis_tabs',
select = TRUE,
tab = tabPanel(
title = paste('Analysis', n),
value = paste0('tab_', n),
plotOutput(paste0('plot_', n)),
actionButton(paste0('close_', n), 'Close')
)
)
})
}renderUI와 insertUI 비교 — 각각 언제 사용할까요
사용 사례에 따라 적절한 도구를 선택하십시오:
- renderUI(): 자리 표시자의 전체 내용을 반응형으로 교체합니다. 전체 블록이 함께 변경될 때 적합합니다.
- insertUI(): 기존 내용에 새 요소를 추가합니다. 모든 내용을 다시 렌더링하지 않고 목록을 확장할 때 적합합니다.
- updateXxxInput(): 기존 입력을 제자리에서 수정합니다. 다시 렌더링하지 않고 선택 항목이나 값을 변경할 때 적합합니다.
- conditionalPanel(): 서버와 통신하지 않고 표시하거나 숨깁니다. 간단한 표시 여부 로직에 적합합니다.
# Decision guide:
# - 'Show filter only when advanced mode' -> conditionalPanel
# - 'Populate column choices from loaded CSV' -> updateSelectInput
# - 'Show different controls per selected tab' -> renderUI
# - 'Add a row editor for each row user adds' -> insertUI
# - 'Remove a row editor' -> removeUI
# Combining strategies:
server <- function(input, output, session) {
# Use renderUI for column selectors (replaces whole block)
output$col_selectors <- renderUI({ ... })
# Use insertUI for dynamically added rows
observeEvent(input$add_row, { insertUI(...) })
# Use conditionalPanel for show/hide (in UI, no server code)
}빠른 확인
Shiny에서 동적 UI를 만들 때 renderUI()와 insertUI()의 핵심적인 차이점은 무엇입니까?
동적 UI 복습
renderUI와 insertUI를 활용한 동적 UI의 핵심 내용:
renderUI({}) + uiOutput('id'): 자리 표시자의 전체 내용을 반응형으로 교체합니다.renderUI()에서tagList()를 반환하여 여러 요소를 한 번에 렌더링합니다.insertUI(selector, where, ui): DOM의 어느 위치에나 요소를 삽입합니다.removeUI(selector): CSS 선택자로 요소를 제거합니다.conditionalPanel(condition, ...): 서버 없이 클라이언트 측에서 표시하거나 숨깁니다.updateSelectInput(),updateSliderInput(): 기존 입력을 제자리에서 수정합니다.- 동적 입력이 렌더링되기 전에
NULL인지 확인하려면 항상req(input$dynamic_id)를 사용하십시오.
# Typical pattern: dynamic column selector
ui <- fluidPage(
fileInput('upload', 'Upload CSV'),
uiOutput('col_ui'), # placeholder
plotOutput('col_plot')
)
server <- function(input, output, session) {
df <- reactive({
req(input$upload)
read.csv(input$upload$datapath)
})
output$col_ui <- renderUI({
req(df())
selectInput('col', 'Column:', choices = names(df()))
})
output$col_plot <- renderPlot({
req(input$col)
hist(df()[[input$col]])
})
}자주 묻는 질문
“renderUI와 insertUI를 활용한 동적 UI” 강의는 무료인가요?
네 — “renderUI와 insertUI를 활용한 동적 UI” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“renderUI와 insertUI를 활용한 동적 UI”에서 뭘 배우나요?
사용자 입력과 서버 상태에 따라 UI 요소를 즉시 생성합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
R Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 R Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“renderUI와 insertUI를 활용한 동적 UI” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 R Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 R Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 반응형 프로그래밍 심화
- 코드 재사용을 위한 Shiny 모듈
- renderUI와 insertUI를 활용한 동적 UI
- Shiny 앱 배포