能否在拆分出app.R、server.R、ui.R的Shiny应用中创建模块?
在拆分的app.R、server.R、ui.R结构中使用Shiny模块的方法
当然可以在拆分文件的Shiny应用里使用模块!你遇到的错误只是一个容易忽略的小失误,咱们一步步来解决:
错误原因分析
你碰到的Warning: Error in force: object 'ui' not found这个报错,根源很明确:你在server.R里错误地添加了shinyApp(ui = ui, server = server)这行代码。
当使用拆分的app.R/server.R/ui.R结构时,Shiny会自动加载ui.R中定义的ui对象和server.R中定义的server函数,只有app.R才是调用shinyApp()的入口文件。server.R里的shinyApp()调用会试图在当前文件环境中寻找ui对象,但这个对象只在ui.R里存在,所以就抛出了“找不到ui”的错误。
解决步骤
只需要做一个简单的修改:
- 删掉
server.R里的shinyApp(ui = ui, server = server)这行代码就可以解决问题!
另外还有个小优化:模块文件hello_world.R只需要在app.R里用source()加载一次就够了,ui.R和server.R不需要重复加载(重复加载也不会报错,但没必要)。
完整的正确代码示例
app.R(应用入口)
library(shiny) # 加载模块函数,只需要在这里source一次 source("hello_world.R") # 唯一调用shinyApp()的地方 shinyApp(ui = ui, server = server)
ui.R(界面定义)
library(shiny) ui <- fluidPage( titlePanel("Using of Shiny modules"), fluidRow( # 调用模块的UI函数 hello_worldUI(id = "id_1") ) )
server.R(逻辑处理)
library(shiny) server <- function(input, output, session) { # 调用模块的服务逻辑函数 callModule(module = hello_world, id = "id_1") }
hello_world.R(模块定义)
# 模块1: hello_world # 模块UI函数 hello_worldUI <- function(id) { ns <- NS(id) fluidPage( fluidRow( column(2, textInput(ns("TI_username"), label = NULL, placeholder = "your name")), column(2, actionButton(ns("AB_hello"), label = "Hello !")) ), hr(), fluidRow( column(12, textOutput(ns("TO_Hello_user"))) ) ) } # 模块服务逻辑函数 hello_world <- function(input, output, session) { # 当用户点击"Hello"按钮时更新响应式变量 name <- eventReactive(input$AB_hello, { input$TI_username }) # 渲染问候语 output$TO_Hello_user <- renderText({ if (name() == "") { "Hello world !" } else { paste("Hello", name(), "!") } }) }
额外注意事项
- 拆分文件结构下,Shiny会自动识别
ui.R的ui对象和server.R的server函数,别在这两个文件里调用shinyApp() - 模块里一定要用
NS(id)包装所有输入输出ID,这是避免命名冲突的关键,你这部分做得很正确! - 如果有多个模块,也可以把所有模块放在一个文件里,或者分多个文件,只要在
app.R里正确source就行。
内容的提问来源于stack exchange,提问作者Corina Roca
相关产品推荐
相关产品推荐

