闪亮:更新输入而不触发反应?

Posted

技术标签:

【中文标题】闪亮:更新输入而不触发反应?【英文标题】:shiny: Update input without reactives getting triggered? 【发布时间】:2019-06-30 19:24:07 【问题描述】:

是否有可能在不触发反应器的情况下更新输入?

下面我举一个最小的例子。目的是在不更改主面板中的值的情况下更新滑块。当滑块再次更改时,应再次将其转发给相关的反应器。

问题和底层用例类似于以下问题:R shiny - possible issue with update***Input and reactivity 和 Update SelectInput without trigger reactive?。与这些问题类似,在我的用例中有一个依赖于两个输入的反应式。我想根据另一个更新这些输入中的一个,这会导致反应被计算两次。但是,这两个问题都通过仅选择性地更新输入来解决问题。这在我的用例中是不可能的,因为我想通过更新输入来向用户显示一些信息。

如果没有可能在不触发响应式响应的情况下更新输入,我将针对我的用例提出后续问题。

示例

library(shiny)

ui <- fluidPage(
   titlePanel("Update Slider - Isolate reaction?"),

   sidebarLayout(
      sidebarPanel(
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30),
         actionButton("set1", "set slider 'bins'$value=20"),
         actionButton("set2", "'ISOLATED' set slider 'bins'$value=20 ")
      ),

      mainPanel(
         textOutput("sliderValue")
      )
   )
)

# Define server logic 
server <- function(input, output, session) 
   output$sliderValue <- renderText(input$bins) 

   observeEvent(input$set1,
     updateSliderInput(session,"bins",value=20)
   )
   observeEvent(input$set2,
     ## Is there any possibility to update the slider without 'sliderValue' changing?
     #isolate does not work
     isolate(
       updateSliderInput(session,"bins",value=20 )
       )
   )


shinyApp(ui = ui, server = server)

【问题讨论】:

【参考方案1】:

这是一个刺,虽然感觉使用陈旧数据可能会产生副作用。使用以下 diff

 # Define server logic
 server <- function(input, output, session) 
-  output$sliderValue <- renderText(input$bins)
+  output$sliderValue <- renderText( saved_bins(); )

+  update <- reactiveVal(TRUE)
+  saved_bins <- reactiveVal(30)
+
+  observeEvent(input$bins, 
+    if (update()) saved_bins(input$bins) else update(TRUE)
+  )
   observeEvent(input$set1,
     updateSliderInput(session,"bins",value=20)
   )
   observeEvent(input$set2,
     ## Is there any possibility to update the slider without 'sliderValue' changing?
     #isolate does not work
+    update(FALSE)
-    isolate(
       updateSliderInput(session,"bins",value=20 )
-    )
   )
 

方法:使用两个新的响应值,一个存储(saved_bins)在渲染中使用的数据,一个(update)存储该数据是否应该更新。所有依赖于input$bins 的东西都应该依赖于saved_bins()。通过使用额外的observeEvent,当您显式设置带有前置update(FALSE) 的一次性“不级联”时,反应性将始终按照最初需要的方式级联除了 .

完整代码如下:

library(shiny)

ui <- fluidPage(
   titlePanel("Update Slider - Isolate reaction?"),

   sidebarLayout(
      sidebarPanel(
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30),
         actionButton("set1", "set slider 'bins'$value=20"),
         actionButton("set2", "'ISOLATED' set slider 'bins'$value=20 ")
      ),

      mainPanel(
         textOutput("sliderValue")
      )
   )
)

# Define server logic 
server <- function(input, output, session) 
  output$sliderValue <- renderText( saved_bins(); ) 

  update <- reactiveVal(TRUE)
  saved_bins <- reactiveVal(30)

  observeEvent(input$bins, 
    if (update()) saved_bins(input$bins) else update(TRUE)
  )
  observeEvent(input$set1,
    updateSliderInput(session,"bins",value=20)
  )
  observeEvent(input$set2,
    ## Is there any possibility to update the slider without 'sliderValue' changing?
    #isolate does not work
    update(FALSE)
    updateSliderInput(session,"bins",value=20)
 )


shinyApp(ui = ui, server = server)

【讨论】:

酷。虽然我有点想知道额外的观察者最终会付出多大的代价......也许从长远来看,可能有可能将它直接包含在 updateXXXInput-commands 中?至少我把它加入了愿望清单:github.com/rstudio/shiny/issues/2324 我理解您的担忧,尽管这是一个“简单的”一维中间observe,如果这有意义的话。只要对input$bins 没有其他反应,我认为双重反应的风险即使不是零也很小。【参考方案2】:

首先感谢@r2evans 的解决方案。

冒着被许多禁止它的校长口头抨击的风险,为避免双重观察者,您可以使用全局分配。不过,使用比 'update' 更通用的名称是明智的。

library(shiny)

ui <- fluidPage(
  titlePanel("Update Slider - Isolate reaction?"),
  
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),
      actionButton("set1", "set slider 'bins'$value=20"),
      actionButton("set2", "'ISOLATED' set slider 'bins'$value=20 ")
    ),
    
    mainPanel(
      textOutput("sliderValue")
    )
  )
)

# Define server logic 
server <- function(input, output, session) 
  output$sliderValue <- renderText( saved_bins(); ) 
  
  saved_bins <- reactiveVal(30)
  
  observeEvent(input$bins, 
    if (update) saved_bins(input$bins) else update <<- TRUE
  )
  observeEvent(input$set1,
    updateSliderInput(session,"bins",value=20)
  )
  observeEvent(input$set2,
    ## Is there any possibility to update the slider without 'sliderValue' changing?
    #isolate does not work
    update <<- FALSE
    updateSliderInput(session,"bins",value=20)
  )


shinyApp(ui = ui, server = server)

【讨论】:

以上是关于闪亮:更新输入而不触发反应?的主要内容,如果未能解决你的问题,请参考以下文章

ggplot2无法识别闪亮的反应数据

R闪亮过滤反应输入

在闪亮的 server.R 中更新数据框而不重新启动应用程序

R中闪亮的反应选择输入

R闪亮的选择输入反应性

删除后如何将旧的反应输入存储在R闪亮中