Dynamiczny interfejs za pomocą renderUI i insertUI
Generuj elementy interfejsu w locie na podstawie danych wejściowych użytkownika i stanu serwera.
Dynamiczny interfejs za pomocą renderUI i insertUI to bezpłatna lekcja R Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej R Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs R Academy zawiera 4 lekcji w sumie.
Dynamiczny interfejs użytkownika — dlaczego i kiedy
Czasami interfejs użytkownika potrzebny w aplikacji nie może zostać w pełni określony podczas jej uruchamiania — zależy on od wyborów użytkownika, wczytanych danych lub warunków występujących w czasie działania. Shiny udostępnia dwa mechanizmy: renderUI() do zastępowania całej zawartości elementu zastępczego oraz insertUI()/removeUI() do dodawania lub usuwania elementów bez zastępowania całej zawartości.
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() i uiOutput()
renderUI({...}) na serwerze tworzy i zwraca reaktywny element interfejsu użytkownika. uiOutput('id') w interfejsie tworzy element zastępczy wyświetlający wszystko, co wygeneruje renderUI. Cała zawartość elementu zastępczego jest zastępowana za każdym razem, gdy obliczenie reaktywne zostanie uruchomione ponownie.
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() z wieloma elementami sterującymi
Zwróć tagList() z renderUI(), aby jednocześnie wygenerować wiele elementów interfejsu użytkownika. Jest to standardowy wzorzec, gdy liczba elementów sterujących zależy od danych — na przykład podczas generowania jednego filtra dla każdej kolumny zbioru danych.
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() — dynamiczne dodawanie elementów
insertUI(selector, where, ui) wstawia element interfejsu użytkownika do DOM bez przebudowy całej strony. Użyj selektorów CSS, aby wskazać miejsce wstawienia. Argument where może przyjmować wartość 'afterEnd', 'beforeEnd', 'afterBegin' lub '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() — usuwanie elementów
removeUI(selector) usuwa pierwszy element DOM pasujący do selektora CSS. Użyj multiple = TRUE, aby usunąć wszystkie pasujące elementy. Jest to uzupełnienie insertUI() w interfejsach opartych na listach, w których użytkownicy mogą dodawać i usuwać elementy.
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() — widoczność po stronie klienta
conditionalPanel(condition, ...) pokazuje lub ukrywa elementy interfejsu użytkownika na podstawie warunku JavaScript ocenianego w przeglądarce. W przeciwieństwie do renderUI() elementy są zawsze obecne w DOM — są tylko widoczne lub ukryte. Jest to szybsze rozwiązanie w przypadku prostej logiki pokazywania i ukrywania, ponieważ nie wymaga komunikacji z serwerem.
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() — modyfikowanie istniejących danych wejściowych
Zamiast zastępować cały element sterujący wejściem, użyj updateSelectInput(session, id, choices, selected), aby zaktualizować tylko opcje lub wybraną wartość istniejącego elementu selectInput. Podobne funkcje aktualizujące istnieją dla wszystkich typów danych wejściowych: updateSliderInput(), updateTextInput() itd.
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() i updateNumericInput()
Funkcje aktualizujące wysyłają do przeglądarki komunikat modyfikujący bieżącą wartość, minimum, maksimum lub etykietę istniejącego elementu wejściowego. Jest to wydajniejsze niż usuwanie i ponowne tworzenie elementu za pomocą renderUI(), a ponadto zachowuje jego położenie w układzie strony.
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))
)
})
}Uzyskiwanie dostępu do danych wejściowych renderUI za pomocą req()
Dane wejściowe utworzone dynamicznie za pomocą renderUI() mają wartość NULL, dopóki nie zostaną wygenerowane. Użyj req(input$dynamic_input) w każdym kodzie serwera zależnym od dynamicznie tworzonych danych wejściowych, aby zapobiec błędom podczas inicjalizacji.
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]])
})
}Dynamiczne karty za pomocą appendTab()
appendTab(inputId, tab, select) dodaje nową kartę do tabsetPanel() w czasie działania aplikacji. removeTab(inputId, target) usuwa kartę. Ten wzorzec umożliwia tworzenie przepływów pracy, w których użytkownicy otwierają, zamykają i przełączają się między dynamicznie generowanymi widokami analiz.
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 a insertUI — kiedy używać którego
Wybierz odpowiednie narzędzie w zależności od przypadku użycia:
- renderUI(): reaktywne zastąpienie całej zawartości elementu zastępczego. Najlepsze rozwiązanie, gdy cały blok zmienia się jednocześnie.
- insertUI(): dodawanie nowych elementów do istniejącej zawartości. Najlepsze rozwiązanie w przypadku rozrastających się list, gdy nie chcesz ponownie renderować całości.
- updateXxxInput(): modyfikowanie istniejącego elementu wejściowego w miejscu. Najlepsze rozwiązanie do zmiany opcji lub wartości bez ponownego renderowania.
- conditionalPanel(): pokazywanie i ukrywanie bez komunikacji z serwerem. Najlepsze rozwiązanie w przypadku prostej logiki widoczności.
# 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)
}Szybkie sprawdzenie
Jaka jest najważniejsza różnica między renderUI() a insertUI() podczas budowania dynamicznego interfejsu użytkownika w Shiny?
Podsumowanie dynamicznego interfejsu użytkownika
Najważniejsze informacje z lekcji „Dynamiczny interfejs użytkownika za pomocą renderUI i insertUI”:
renderUI({}) + uiOutput('id'): reaktywne zastępowanie całej zawartości elementu zastępczego.- Zwracaj
tagList()zrenderUI(), aby jednocześnie generować wiele elementów. insertUI(selector, where, ui): wstawianie elementów w dowolnym miejscu DOM.removeUI(selector): usuwanie elementów za pomocą selektora CSS.conditionalPanel(condition, ...): pokazywanie i ukrywanie po stronie klienta bez udziału serwera.updateSelectInput(),updateSliderInput(): modyfikowanie istniejących danych wejściowych w miejscu.- Zawsze używaj
req(input$dynamic_id), aby sprawdzać, czy wartość nie jest NULL, zanim dynamiczne dane wejściowe zostaną wygenerowane.
# 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]])
})
}Często zadawane pytania
Czy lekcja „Dynamiczny interfejs za pomocą renderUI i insertUI” jest bezpłatna?
Tak — pełny tekst „Dynamiczny interfejs za pomocą renderUI i insertUI” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu R Academy, przejdź na CoddyKit PRO. Kurs R Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Dynamiczny interfejs za pomocą renderUI i insertUI”?
Generuj elementy interfejsu w locie na podstawie danych wejściowych użytkownika i stanu serwera. Ćwiczysz R Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć R Academy?
Nie wymagamy żadnego doświadczenia. R Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Dynamiczny interfejs za pomocą renderUI i insertUI”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji R Academy?
Tak. Każda lekcja R Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Zaawansowane programowanie reaktywne
- Moduły Shiny wielokrotnego użytku
- Dynamiczny interfejs za pomocą renderUI i insertUI
- Wdrażanie aplikacji Shiny