Shiny应用中R6类私有字段更新后UI无响应问题咨询
问题成因
Shiny的响应式渲染仅会监听*响应式对象(reactiveVal/reactiveValues)*的变化,你当前把..counter、..desc都定义为普通R6私有字段,修改这些普通变量时,Shiny的渲染函数renderText无法感知到数据更新,因此不会触发UI重绘,这就是UI没有变化的根本原因。
可行解决方案
直接将需要响应式更新的变量替换为Shiny的响应式对象即可,无需重构现有R6类的整体结构,修改成本极低。核心修改点如下:
- 把
..counter和..desc从普通变量改成reactiveVal类型 - 所有读取这两个值的地方都加
(),比如private$..counter() - 所有修改这两个值的地方用函数赋值写法,比如
private$..counter(新值)
完整修改后可运行代码
library(R6) library(stringi) library(shiny) df <- data.frame(dp = c("dp1", "dp2", "dp3"), desc = c("problem 1", "problem 2", "problem 3")) app <- R6::R6Class(classname = "App", private = list( #unique string id ..id = stringi::stri_rand_strings(1, 18), #the data to be iterated through ..df = df, # 将counter改为响应式变量 ..counter = reactiveVal(1), #initiating the dp and desc ..dp = 'dp1', # 将desc改为响应式变量 ..desc = reactiveVal('problem 1'), #the underlying server, to be created like a normal server .server = function(input, output, session){ output$text <- renderText({ # 响应式变量取值加() private$..desc() }) observeEvent(input$button, { # 响应式变量赋值用函数写法 private$..counter(private$..counter() + 1) self$update_private() #check the private content since the print is not updating print(private$..counter()) print(private$..dp) print(private$..desc()) }) } ), public = list( #create names for ui elements button = NULL, text = NULL, initialize = function(){ self$button <- self$get_id("button") self$text <- self$get_id("text") self$update_private() }, #gives ui outputs unique names tied to the user's id get_id = function(name, ns = NS(NULL)){ ns <- NS(ns(private$..id)) id <- ns(name) return(id) }, #automatically updates the private field based on the counter update_private = function(){ counter_val <- private$..counter() if(counter_val == 1){ private$..dp <- "dp1" } else if(counter_val == 2){ private$..dp <- "dp2" } else{ private$..dp <- "dp3" } # 更新desc响应式变量的值 private$..desc(private$..df[private$..df$dp == private$..dp, "desc"]) }, ui = function(){ fluidPage( h1("An Example"), mainPanel( textOutput(self$text)), sidebarPanel( shiny::actionButton(inputId = self$button, label = 'Update!', width = '100%' )) ) },#end ui server = function(input, output, session){ callModule(module = private$.server, id = private$..id) } ) ) test <- app$new() ui <- test$ui() server <- function(input, output, session) { test$server() } shinyApp(ui = ui, server = server)
内容的提问来源于stack exchange,提问作者mauraeh
相关产品推荐
相关产品推荐

