0Pricing
R Academy · Lekcja

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() z renderUI(), 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

  1. Zaawansowane programowanie reaktywne
  2. Moduły Shiny wielokrotnego użytku
  3. Dynamiczny interfejs za pomocą renderUI i insertUI
  4. Wdrażanie aplikacji Shiny
← Powrót do R Academy