Modules Shiny pour réutiliser le code
Encapsulez la logique de l’interface et du serveur dans des modules réutilisables et dotés d’un espace de noms.
Modules Shiny pour réutiliser le code est une leçon R Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage R Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours R Academy comprend 4 leçons au total.
Pourquoi utiliser des modules Shiny ?
À mesure que les applications Shiny grandissent, regrouper tout le code d’interface et de serveur dans un seul fichier devient ingérable. Les modules sont des éléments autonomes qui regroupent une interface Shiny et une logique serveur, avec des identifiants préfixés par un espace de noms. Vous pouvez réutiliser le même module plusieurs fois dans une application sans conflit d’identifiants, et tester les modules indépendamment.
# 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() — La fonction d’espace de noms
Chaque fonction d’interface de module commence par ns <- NS(id). Tous les identifiants des éléments d’interface transmis à Shiny doivent être enveloppés dans ns(). Cette fonction ajoute id- au début de chaque identifiant et crée ainsi un espace de noms qui empêche les conflits entre les instances d’un module.
# 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() — La fonction serveur
moduleServer(id, function(input, output, session) {...}) est la méthode moderne (Shiny 1.5 ou version ultérieure) pour définir la logique serveur d’un module. Dans la fonction, input, output et session utilisent automatiquement l’espace de noms du module : vous accédez à input$dataset, et non à 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])
})
})
}Utiliser des modules dans l’application
Appelez la fonction d’interface du module dans ui et sa fonction serveur dans server, en utilisant dans les deux cas la même chaîne id. Vous pouvez appeler plusieurs fois le même module avec des identifiants différents afin de créer des instances indépendantes.
# 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)Transmettre des paramètres à l’interface du module
Les fonctions d’interface des modules sont de simples fonctions R. Ajoutez des paramètres supplémentaires après id pour personnaliser l’apparence ou le comportement de chaque instance au moment de sa création. Ces paramètres sont évalués une seule fois, lors de la construction de l’interface.
# 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')Transmettre des réactifs INTO un module
Les fonctions serveur des modules peuvent accepter des valeurs ou des expressions réactives comme paramètres. L’application parente peut ainsi transmettre des données aux modules enfants. Dans le module, appelez le réactif comme une fonction pour obtenir sa valeur actuelle.
# 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)
}Renvoyer des réactifs FROM un module
Les fonctions serveur des modules peuvent renvoyer des valeurs réactives à l’application parente. Les modules enfants peuvent ainsi communiquer vers le haut. Renvoyez un réactif ou une liste de réactifs depuis moduleServer(), puis récupérez-le dans la fonction serveur parente.
# 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()) })
}Organisation des fichiers des modules
Pour les grandes applications, placez chaque module dans son propre fichier, dans un dossier R/. Shiny charge automatiquement tous les fichiers du dossier R/ au démarrage de l’application. Chaque module reste ainsi autonome et peut être testé indépendamment avec le paquet 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)Modules imbriqués
Les modules peuvent contenir d’autres modules. Le module parent transmet son propre espace de noms session aux appels des modules enfants au moyen de l’argument session. Chaque niveau d’imbrication ajoute un préfixe d’espace de noms : 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-elementTester des modules avec shinytest2
Le paquet shinytest2 vous permet d’écrire des tests automatisés pour les modules en les enveloppant dans une application minimale. Utilisez AppDriver pour piloter le navigateur, définir les entrées et vérifier les valeurs de sortie, le tout sans session de navigateur réelle.
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')))
})Modes de communication entre modules
Voici un résumé des modes de communication entre les modules et l’application parente :
- Du parent vers le module : transmettre un réactif comme paramètre à la fonction serveur du module.
- Du module vers le parent : renvoyer un réactif depuis moduleServer().
- Entre modules frères : le parent conserve l’état partagé (
reactiveValues) et le transmet à chaque module. - État global : utiliser
reactiveValuesdéfini dans le parent et transmettre des références aux modules enfants.
# 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
}Vérification rapide
Pourquoi tous les identifiants des éléments d’interface d’une fonction d’interface de module doivent-ils être enveloppés dans ns() ?
Récapitulatif des modules Shiny
Points essentiels des modules Shiny pour réutiliser le code :
- Les modules empêchent les conflits d’identifiants en ajoutant un espace de noms à tous les identifiants avec
NS(id). - Interface du module : fonction standard avec
ns <- NS(id); enveloppez tous les identifiants dansns(). - Serveur du module :
moduleServer(id, function(input, output, session) {...}). - Transmettez les réactifs INTO les modules comme paramètres de fonction ; RETURN les réactifs pour communiquer vers le parent.
- Appelez plusieurs fois le même module avec des identifiants différents pour créer des instances indépendantes.
- Organisez les modules dans des fichiers
R/mod_*.R; Shiny charge automatiquement le dossierR/. - Testez les modules avec
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)Apprends R avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 43
- Leçons
- 159
Questions Fréquemment Posées
La leçon « Modules Shiny pour réutiliser le code » est-elle gratuite ?
Oui — le texte complet de « Modules Shiny pour réutiliser le code » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours R Academy, passe à CoddyKit PRO. Le cours R Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Modules Shiny pour réutiliser le code » ?
Encapsulez la logique de l’interface et du serveur dans des modules réutilisables et dotés d’un espace de noms. Tu pratiques R Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer R Academy ?
Aucune expérience préalable n'est requise. R Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « Modules Shiny pour réutiliser le code » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon R Academy ?
Oui. Chaque leçon R Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Approfondissement de la programmation réactive
- Modules Shiny pour réutiliser le code
- Interface dynamique avec renderUI et insertUI
- Déployer des applications Shiny