官方文档
https://shiny.posit.co/r/getstarted/shiny-basics/lesson1/index.html
https://www.rdocumentation.org/packages/shiny/versions/1.9.1
如何写自己的shiny module
ref:
https://shiny.posit.co/r/articles/improve/modules/
需要自定义 shiny module的场景:
- shiny 包内置的模块(UI / server函数)不能满足自己的要求
- 当shiny app的代码很长,需要模块化封装
其他 ……
命名空间 ns()
解决id冲突的问题
在shiny 中,InputId
, OutputId
等都需要满足在各自的命名空间内的ID 唯一性, 即InputId
, OutputId
各自存在于不同的命名空间,只要在各自的命名空间内的ID不冲突,程序就不会报错。
自定义 module
- 自定义一个 计数按钮控件
counterButton
library(shiny)
counterButton <- function(id, label = "Counter") {
# 所有 UI 函数体都应以此行开头, 它采用字符串 id 并创建一个命名空间函数。
# 保证该命名空间内的Id唯一即可。即 “button” “out” 在该命名空间内唯一,而不是在整个应用程序中是唯一的。
ns <- NS(id)
# 函数体中出现的所有 InputId 和 OutputId 都需要包装在对 ns()中。
# 如果你的UI控件是多组件,用 tagList() 包裹起来;如果你的UI控件是单个控件,可以直接使用,或者使用 div() 包裹。
tagList(
actionButton(ns("button"), label = label),
verbatimTextOutput(ns("out"))
)
}
- 编写 自定义控件的服务器逻辑 ``
server 逻辑被封装在一个函数中,我们称之为模块 module server function。
需要 对 moduleServer()
调用进行,
他接收两个参数: 第一个是 id
,第二个是 module function()
每个模块函数都必须采用这三个参数。moduleServer() 函数以特殊方式调用 module 函数,该函数创建可识别 ID 的特殊 input、output 和 session 对象。
counterServer <- function(id) {
moduleServer(
id,
function(input, output, session) {
count <- reactiveVal(0)
# 检测 按钮触发事件, 当按钮按下,计数 + 1
observeEvent(input$button, {
count(count() + 1)
})
# UI 控件显示计数值
output$out <- renderText({
count()
})
count
}
)
}
自定义 shiny module 的调用
# 指定调用时的 计数控件的ID, 这在内部会生成一个名为 counter1 的命名空间,
# counter1 命名空间的内部,具有ID 为 "button" 和 "out" 的控件
ui <- fluidPage(
counterButton("counter1", "Counter #1")
)
# 调用 计数控件的server逻辑, 指定调用的控件id, "counter1".
# 这样就可以调用counter1 命名空间的变量: input$button 和 output$out
server <- function(input, output, session) {
counterServer("counter1")
}
# 关联 UI 和 server的逻辑
shinyApp(ui, server)
至此, 一个完整的 自定义 shiny module,及其 shiny app 的调用就完成了。