Modul Shiny untuk Penggunaan Ulang Kode
Bungkus logika UI dan server ke dalam modul yang memiliki ruang nama dan dapat digunakan ulang.
Modul Shiny untuk Penggunaan Ulang Kode adalah pelajaran R Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar R Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus R Academy mencakup 4 pelajaran total.
Mengapa Menggunakan Modul Shiny?
Seiring bertambah besarnya aplikasi Shiny, menempatkan seluruh kode UI dan server dalam satu berkas menjadi sulit dikelola. Modul adalah bagian UI Shiny dan logika server yang berdiri sendiri, dengan ID yang memiliki ruang nama. Anda dapat menggunakan kembali modul yang sama beberapa kali dalam satu aplikasi tanpa konflik ID, serta menguji modul secara terpisah.
# Problem: without modules, ID conflicts arise
# ui <- fluidPage(
# selectInput('dataset', ...), # used by plot1 AND plot2!
# selectInput('dataset', ...) # duplicate ID — BROKEN
# )
# With modules: each instance has its own namespaced IDs
# plotModule('plot1', ...) -> input$plot1-dataset
# plotModule('plot2', ...) -> input$plot2-datasetNS() — Fungsi Ruang Nama
Setiap fungsi UI modul diawali dengan ns <- NS(id). Semua ID elemen UI yang diteruskan ke Shiny harus dibungkus dengan ns(). Fungsi ini menambahkan awalan id- ke setiap ID sehingga membuat ruang nama yang mencegah konflik antarinstans modul.
# Module UI function
filter_plot_ui <- function(id) {
ns <- NS(id) # create the namespace function
tagList(
selectInput(ns('dataset'), 'Choose Dataset:',
choices = c('mtcars', 'iris', 'airquality')),
sliderInput(ns('n_rows'), 'Rows to show:', 1, 50, 20),
plotOutput(ns('scatter_plot'))
)
}moduleServer() — Fungsi Server
moduleServer(id, function(input, output, session) {...}) adalah cara modern (Shiny 1.5+) untuk mendefinisikan logika server modul. Di dalam fungsi tersebut, input, output, dan session otomatis menggunakan ruang nama modul — Anda mengakses input$dataset, bukan input$plot1-dataset.
# Module server function
filter_plot_server <- function(id) {
moduleServer(id, function(input, output, session) {
data <- reactive({
# input$dataset is already namespaced to this instance
head(get(input$dataset), input$n_rows)
})
output$scatter_plot <- renderPlot({
df <- data()
plot(df[[1]], df[[2]],
xlab = names(df)[1], ylab = names(df)[2])
})
})
}Menggunakan Modul dalam Aplikasi
Panggil fungsi UI modul di dalam ui dan fungsi server modul di dalam server, keduanya menggunakan string id yang sama. Anda dapat memanggil modul yang sama beberapa kali dengan ID berbeda untuk membuat instans yang saling independen.
# Main app using the module twice
ui <- fluidPage(
h2('Plot 1'),
filter_plot_ui('plot1'), # instance 1
hr(),
h2('Plot 2'),
filter_plot_ui('plot2') # instance 2 — no ID conflicts!
)
server <- function(input, output, session) {
filter_plot_server('plot1') # wire up instance 1
filter_plot_server('plot2') # wire up instance 2
}
shinyApp(ui, server)Meneruskan Parameter ke UI Modul
Fungsi UI modul hanyalah fungsi R biasa. Tambahkan parameter tambahan selain id untuk menyesuaikan tampilan atau perilaku setiap instans saat dibuat. Parameter ini dievaluasi satu kali ketika UI dibangun.
# Module UI with extra parameters
summary_table_ui <- function(id, title = 'Summary', height = '300px') {
ns <- NS(id)
tagList(
h4(title),
div(
style = paste0('height:', height, '; overflow-y: auto;'),
DTOutput(ns('tbl'))
)
)
}
# Use with custom titles
summary_table_ui('train_tbl', title = 'Training Data', height = '400px')
summary_table_ui('test_tbl', title = 'Test Data', height = '200px')Meneruskan Nilai Reaktif INTO Modul
Fungsi server modul dapat menerima nilai atau ekspresi reaktif sebagai parameter. Dengan demikian, aplikasi induk dapat meneruskan data ke modul anak. Di dalam modul, panggil nilai reaktif seperti fungsi untuk mendapatkan nilainya saat ini.
# Module that accepts a reactive as input
chart_module_server <- function(id, data_reactive) {
moduleServer(id, function(input, output, session) {
output$chart <- renderPlot({
df <- data_reactive() # call the reactive passed in
ggplot2::ggplot(df, ggplot2::aes(x = x, y = y)) +
ggplot2::geom_point(colour = input$colour)
})
})
}
# In main server:
server <- function(input, output, session) {
shared_data <- reactive({ load_data(input$source) })
chart_module_server('chart1', data_reactive = shared_data)
chart_module_server('chart2', data_reactive = shared_data)
}Mengembalikan Nilai Reaktif FROM Modul
Fungsi server modul dapat mengembalikan nilai reaktif ke aplikasi induk. Dengan demikian, modul anak dapat berkomunikasi ke atas. Kembalikan nilai reaktif atau daftar nilai reaktif dari moduleServer(), lalu simpan hasilnya dalam fungsi server induk.
# Module that returns a reactive to the parent
filter_module_server <- function(id, all_data) {
moduleServer(id, function(input, output, session) {
# Return the filtered data reactive
filtered <- reactive({
all_data[all_data$group == input$group_filter, ]
})
return(filtered) # parent can use this reactive
})
}
# In main server:
server <- function(input, output, session) {
raw_data <- reactive({ read.csv('data.csv') })
# filtered_data is a reactive returned from the module
filtered_data <- filter_module_server('filter1', raw_data)
output$main_plot <- renderPlot({ plot(filtered_data()) })
}Pengaturan Berkas Modul
Untuk aplikasi berukuran besar, tempatkan setiap modul dalam berkasnya sendiri di folder R/. Shiny secara otomatis memuat semua berkas dalam R/ ketika aplikasi dimuat. Dengan demikian, setiap modul tetap berdiri sendiri dan dapat diuji secara terpisah menggunakan paket shinytest2.
# Recommended project structure:
# myapp/
# app.R # main app: source modules + wire up
# R/
# mod_filter_plot.R # filter_plot_ui() + filter_plot_server()
# mod_summary_table.R # summary_table_ui() + summary_table_server()
# mod_download.R # download_ui() + download_server()
# tests/
# testthat/test-mod_filter_plot.R
# In app.R:
library(shiny)
# source('R/mod_filter_plot.R') # not needed if in R/ folder
ui <- fluidPage(filter_plot_ui('p1'))
server <- function(input, output, session) { filter_plot_server('p1') }
shinyApp(ui, server)Modul Bertingkat
Modul dapat berisi modul lain. Modul induk meneruskan ruang nama session-nya sendiri ke pemanggilan modul anak menggunakan argumen session. Setiap tingkat penyarangan menambahkan awalan ruang nama lain: outer-inner-element_id.
# Outer module uses an inner module
outer_server <- function(id) {
moduleServer(id, function(input, output, session) {
# Call an inner module using this module's session
inner_result <- inner_module_server(
id = 'inner',
session = session # passes the namespaced session
)
output$combined <- renderText({
paste('Inner result:', inner_result())
})
})
}
# ID chain: outer -> inner
# Full ID: outer-inner-elementMenguji Modul dengan shinytest2
Paket shinytest2 memungkinkan Anda menulis pengujian otomatis untuk modul dengan membungkusnya dalam aplikasi minimal. Gunakan AppDriver untuk mengendalikan peramban, menetapkan nilai masukan, dan memeriksa nilai keluaran — semuanya tanpa sesi peramban sungguhan.
library(shinytest2)
# Wrap the module in a testable app
test_that('filter_plot module filters correctly', {
test_app <- shinyApp(
ui = fluidPage(filter_plot_ui('test')),
server = function(input, output, session) {
filter_plot_server('test')
}
)
app <- AppDriver$new(test_app)
app$set_inputs('test-dataset' = 'iris') # namespaced input
app$wait_for_idle()
# Assert plot was rendered
expect_true(!is.null(app$get_value(output = 'test-scatter_plot')))
})Pola Komunikasi Modul
Berikut rangkuman pola komunikasi antara modul dan aplikasi induk:
- Induk ke Modul: meneruskan nilai reaktif sebagai parameter ke server modul.
- Modul ke Induk: mengembalikan nilai reaktif dari moduleServer().
- Antarmodul Bersaudara: induk menyimpan status bersama (reactiveValues) dan meneruskannya ke setiap modul.
- Status Global: gunakan
reactiveValuesyang didefinisikan di induk, lalu teruskan referensinya ke bawah.
# Sibling module communication via parent state
server <- function(input, output, session) {
shared <- reactiveValues(selected_row = NULL)
# Table module sets the selection
table_module_server('tbl', shared_state = shared)
# Detail module reads the selection
detail_module_server('detail', shared_state = shared)
# Both modules communicate through 'shared' reactiveValues
# Table sets shared$selected_row; Detail reads it
}Pemeriksaan Singkat
Mengapa semua ID elemen UI dalam fungsi UI modul harus dibungkus dengan ns()?
Rangkuman Modul Shiny
Hal-hal penting dari Modul Shiny untuk Penggunaan Ulang Kode:
- Modul mencegah konflik ID dengan memberikan ruang nama pada semua ID menggunakan
NS(id). - UI modul: fungsi biasa dengan
ns <- NS(id); bungkus semua ID denganns(). - Server modul:
moduleServer(id, function(input, output, session) {...}). - Teruskan nilai reaktif INTO modul sebagai parameter fungsi; RETURN nilai reaktif untuk komunikasi ke atas.
- Panggil modul yang sama beberapa kali dengan ID berbeda untuk membuat instans yang independen.
- Atur modul dalam berkas
R/mod_*.R; Shiny secara otomatis memuat folderR/. - Uji modul dengan
shinytest2::AppDriver.
# Complete module example
my_module_ui <- function(id) {
ns <- NS(id)
tagList(selectInput(ns('var'), 'Variable:', choices = names(mtcars)),
plotOutput(ns('hist')))
}
my_module_server <- function(id, data) {
moduleServer(id, function(input, output, session) {
output$hist <- renderPlot(hist(data()[[input$var]]))
})
}
# Use it:
ui <- fluidPage(my_module_ui('m1'), my_module_ui('m2'))
server <- function(input, output, session) {
d <- reactive(mtcars)
my_module_server('m1', d)
my_module_server('m2', d)
}
shinyApp(ui, server)Pertanyaan yang Sering Diajukan
Apakah pelajaran “Modul Shiny untuk Penggunaan Ulang Kode” gratis?
Ya — teks lengkap “Modul Shiny untuk Penggunaan Ulang Kode” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus R Academy, upgrade ke CoddyKit PRO. Kursus R Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Modul Shiny untuk Penggunaan Ulang Kode”?
Bungkus logika UI dan server ke dalam modul yang memiliki ruang nama dan dapat digunakan ulang. Kamu berlatih R Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai R Academy?
Tidak diperlukan pengalaman sebelumnya. R Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Modul Shiny untuk Penggunaan Ulang Kode” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran R Academy ini?
Ya. Setiap pelajaran R Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Pendalaman Pemrograman Reaktif
- Modul Shiny untuk Penggunaan Ulang Kode
- UI Dinamis dengan renderUI dan insertUI
- Menerapkan Aplikasi Shiny