拆分多Shiny应用整合至shinydashboard时出现input/output未找到错误如何解决
Shiny多子应用拆分脚本报错解决方案
报错根因
你遇到的报错是因为sub2.R同时包含UI和server代码,且你在主脚本的两个不同上下文环境中重复执行了该文件:
- 第一次在UI定义区域source
sub2.R时,仅需要用到subItem2、Tab_sub2两个UI对象,但文件中server逻辑(reactiveValues、observeEvent、output赋值)也会同步执行,此时环境中不存在只有server函数内部才有的input、output参数,直接触发找不到对象的错误。 - 第二次在server函数内部source
sub2.R时虽然环境参数齐全,但第一次执行已经抛出错误。
你的拆分需求完全可以实现,以下是两种常用的正确实现方式:
方案1:拆分UI和server为独立文件(最直观不易出错)
将每个子应用的UI代码和server代码拆分到两个独立文件,按需引入:
- 新建
sub2_ui.R,仅存放UI相关代码:
### ------ Ui part subItem2 = menuSubItem(tabName = "sub2", text = "Second subItem") Tab_sub2 = tabItem(tabName = "sub2", fluidPage( actionButton(inputId = "run_sub2", label = "Run"), conditionalPanel(condition = "$('html').hasClass('shiny-busy')", tags$div('Please wait 5 seconds ... ')), textOutput(outputId = "timer_sub2") ))
- 新建
sub2_server.R,仅存放server相关代码:
### -------- Server part Memory_sub2 = reactiveValues() observeEvent(input$run_sub2,{ Memory_sub2$timerStart = proc.time() Sys.sleep(5) Memory_sub2$timerEnd = proc.time() }) output$timer_sub2 = renderText({ Memory_sub2$timerEnd[3]- Memory_sub2$timerStart[3] })
- 修改主脚本
Main.R的引入逻辑:- UI区域仅引入UI文件:
source(file = "sub2_ui.R", local = TRUE) - server函数内部仅引入server文件:
source(file = "sub2_server.R", local = TRUE)
- UI区域仅引入UI文件:
方案2:server逻辑封装为函数(适合多子应用场景,避免变量冲突)
如果子应用数量多,担心变量重名,可以把每个子应用的server逻辑封装为函数,和UI代码放在同一个文件:
- 修改
sub2.R代码如下:
### ------ Ui part subItem2 = menuSubItem(tabName = "sub2", text = "Second subItem") Tab_sub2 = tabItem(tabName = "sub2", fluidPage( actionButton(inputId = "run_sub2", label = "Run"), conditionalPanel(condition = "$('html').hasClass('shiny-busy')", tags$div('Please wait 5 seconds ... ')), textOutput(outputId = "timer_sub2") )) ### -------- Server part 封装为函数 sub2_server = function(input, output, session){ Memory_sub2 = reactiveValues() observeEvent(input$run_sub2,{ Memory_sub2$timerStart = proc.time() Sys.sleep(5) Memory_sub2$timerEnd = proc.time() }) output$timer_sub2 = renderText({ Memory_sub2$timerEnd[3]- Memory_sub2$timerStart[3] }) }
- 修改主脚本
Main.R逻辑:- UI区域正常source
sub2.R,此时仅定义UI对象和server函数,不会执行server逻辑,不会触发报错 - server函数内部调用封装好的server函数即可:
sub2_server(input, output, session)
- UI区域正常source
如果子应用复杂度更高,还可以使用Shiny官方的模块(Module)功能,进一步隔离不同子应用的命名空间,避免inputId重名冲突。
内容的提问来源于stack exchange,提问作者Alejo
相关产品推荐
相关产品推荐

