如何将Shiny应用的reactiveValues对象传入全局环境查看?
Shiny模块间共享的reactiveValues对象如何传入全局环境查看完整内容
问题场景
我用Shiny的模块结构做数据双向传递练习:主server中定义common <- reactiveValues(),在mod1、mod2模块间传递并修改数据,程序运行正常——顶部显示基础数据框df,滑块输入乘数后第二个表格展示相乘结果,第三个表格将结果加10并把A列传回第二个表格,第二个表格再把最后一列乘100传回第三个表格。
但开发调试时需要查看common对象的完整内容,之前尝试:
oe1 <- reactive({common}) observeEvent(oe1(),{common.R <<- oe1()})
得到的只是元信息:
> common.R <ReactiveValues> Values: colA_mod2, df, mod1_dat, mod2_table, svc Readonly: FALSE
看不到具体元素的值,且不想用print()让控制台滚屏(最终对象会很庞大)。
解决方案
核心是把reactiveValues对象转换为普通R列表(而非直接传递对象引用),同时处理其中嵌套的reactive对象,手动取出其当前值。
修改主server中的代码,替换原来的oe1和observeEvent部分:
# 监听common的变化,转成普通列表传入全局环境 observe({ # 将reactiveValues转为普通列表 common_list <- reactiveValuesToList(common) # 处理列表中的reactive对象(比如common$svc是reactive,需要取出当前值) for(name in names(common_list)){ if(is.reactive(common_list[[name]])){ common_list[[name]] <- common_list[[name]]() } } # 赋值到全局环境 common.R <<- common_list })
说明
reactiveValuesToList()函数会把reactiveValues中的所有键值对提取为普通列表,这样就能直接查看每个元素的具体内容;- 因为
common$svc是一个reactive对象(而非直接的值),reactiveValuesToList()不会自动解析它,所以需要遍历列表,判断并取出每个reactive对象的当前值; - 修改后,在RStudio控制台输入
common.R就能看到所有元素的具体内容,比如:
> str(common.R) List of 5 $ df :'data.frame': 2 obs. of 2 variables: ..$ A: int [1:2] 1 2 ..$ B: int [1:2] 3 4 $ svc : num 1 $ mod1_dat :'data.frame': 2 obs. of 2 variables: ..$ A: num [1:2] 1 2 ..$ B: num [1:2] 3 4 $ mod2_table:'data.frame': 2 obs. of 2 variables: ..$ A: num [1:2] 11 12 ..$ B: num [1:2] 13 14 $ colA_mod2 : num [1:2] 11 12
修改后的完整代码
library(shiny) library(DT) mod1_ui <- function(id) { ns <- NS(id) DTOutput(ns("tbl")) } mod1_server <- function(id, common) { moduleServer(id, function(input, output, session) { new_dat <- reactive({ df <- common$df svc <- common$svc() df * as.numeric(svc) }) observe({ common$mod1_dat <- new_dat() # 避免mod2_table未初始化时报错 if(!is.null(common$mod2_table)){ common$colA_mod2 <- common$mod2_table$A } }) output$tbl <- renderDT({ dat <- new_dat() if(!is.null(common$colA_mod2)){ dat$colA_mod2 <- common$colA_mod2 } dat }) }) } mod2_ui <- function(id) { ns <- NS(id) DTOutput(ns("tbl")) } mod2_server <- function(id, common) { moduleServer(id, function(input, output, session) { output$tbl <- renderDT({ mod1_dat <- common$mod1_dat dat <- data.frame(mod1_dat + 10) if (!is.null(common$colA_mod2)) { dat$colA_mod2_mod1 <- common$colA_mod2 * 100 } common$mod2_table <- dat dat }) }) } ui <- fluidPage( mainPanel( DTOutput("table"), sliderInput("svc", "", min = 0, max = 10, value = 1), mod1_ui("mod1"), mod2_ui("mod2") ) ) server <- function(input, output, session) { common <- reactiveValues(df = data.frame(A = 1:2, B = 3:4)) output$table <- renderDT({datatable(common$df)}) common$svc <- reactive(input$svc) mod1_server("mod1", common) mod2_server("mod2", common) # 修改后的全局赋值代码 observe({ common_list <- reactiveValuesToList(common) for(name in names(common_list)){ if(is.reactive(common_list[[name]])){ common_list[[name]] <- common_list[[name]]() } } common.R <<- common_list }) } shinyApp(ui, server)
内容的提问来源于stack exchange,提问作者Curious Jorge - user9788072
相关产品推荐
相关产品推荐

