繁体   English   中英

使用反应式值和反应式表达式来触发观察事件

[英]Using a reactive value and a reactive expression to trigger an observeEvent

下面应用程序中的模块包含一个具有两个触发器的观察者:

  1. 一个反应值input$trigger1 (在模块服务器内呈现的 fileInput 的值)
  2. 反应式表达式trigger2() (表达式返回主应用程序中提供给模块的 actionButton 的值)。

我希望观察者在被这两个值中的任何一个更改触发时将一些文本打印到控制台。

尝试 1:我尝试将触发器包装在向量中:

  observeEvent(c(input$trigger1, trigger2()), print('the one with the vector'), ignoreInit = T)

问题:当复选框被选中时,这个 observeEvent 被触发。

我认为这可能与在应用程序启动时立即调用模块的服务器有关,而模块的 UI 仅在input$check == TRUE时才呈现? 我尝试通过使用observe()input$trigger1trigger2()的值打印到控制台来对此进行调查。 启动时,打印到控制台的trigger2(): 0 input$trigger1: NULL 当复选框被选中时, input$trigger1仍然是NULL但观察者再次触发并将input$trigger1: NULL打印到控制台。 也许这是由于启动时 DOM 中不存在trigger1

所以我尝试同时调用模块的服务器和 UI,如下所示:

output$form = renderUI({req(input$check); modUI('mod')})

observeEvent(input$check, {
    req(input$check)
    callModule(modServer, 'mod', trigger2 = reactive(input$trigger2))
})

但是input$trigger1的值仍然会打印到控制台两次,这一次是在选中复选框时。 我不知道为什么,因为两次都是NULL


尝试 2: 根据该线程中的一篇文章,我发现由于input$trigger1trigger()具有不同的类,因此将它们包装在一个向量中可能是问题的根源(因为 R 将它们强制为相同的 class通过链接的帖子出来)。 所以我尝试使用花括号代替:

  observeEvent({input$trigger1; trigger2()}, print('the one with curly braces'), ignoreInit = T)

问题:该观察者响应trigger2()的变化,但不响应input$trigger1的变化。 也许这与eventExpr ( trigger2() ) 的返回值有关,如果input$trigger1更改,则不会更改,但是由于eventExpr是反应式表达式,因此对input$trigger1trigger2()的更改应该使其无效像在这篇文章中一样触发观察者。


尝试 3:我尝试交换触发器的顺序:

  observeEvent({trigger2(); input$trigger1}, print('the one with curly braces with the order swapped around'), ignoreInit = T)

问题:这一次观察者响应两个触发器,但前提input$trigger1 首先被改变。 否则,它是无响应的。


这是可重现的代码:

 library("shiny") # MODULE UI --------------------------------------------------------------- modUI = function(id) { ns = NS(id) uiOutput(ns('ui')) } # MODULE SERVER ----------------------------------------------------------- modServer = function(input, output, session, trigger2) { ns = session$ns output$ui = renderUI(fileInput(ns('trigger1'), 'Trigger1')) #OBSERVER 1 --------------------------------------------- observeEvent(c(input$trigger1, trigger2()), print('the one with the vector'), ignoreInit = T) # observe(print(list(`trigger2 (actionButton)` = trigger2()))) # observe(print(list(`trigger1 (fileInput)`= input$trigger1))) #OBSERVER 2 --------------------------------------------- # observeEvent({input$trigger1; trigger2()}, print('the one with curly braces'), ignoreInit = T) #OBSERVER 3 --------------------------------------------- # observeEvent({trigger2(); input$trigger1}, print('the one with curly braces with the order swapped around'), ignoreInit = T) } # MAIN APP ---------------------------------------------------------------- ui <- fluidPage( checkboxInput('check', 'Show'), uiOutput('form'), actionButton('trigger2', 'Trigger 2') ) server <- function(input, output, session) { output$form = renderUI({req(input$check); modUI('mod')}) # observe({ # req(input$check) # callModule(modServer, 'mod', trigger2 = reactive(input$trigger2)) # }) callModule(modServer, 'mod', trigger2 = reactive(input$trigger2)) } shinyApp(ui = ui, server = server)

我已经尝试了我能想到的一切来隔离问题,但无济于事,因此非常感谢任何和所有的指导。

更新:也许它与input$file作为data.frame的值有关? 我尝试用trigger1()替换input$trigger1 ,每次input$trigger1更改时,reactiveVal 都会增加 1。 这样,两个触发器都具有相同的 class 和长度(即 numeric(1))。 结果观察者按预期工作:

modServer = function(input, output, session, trigger2) {

  ns = session$ns

  trigger1 = reactiveVal(0)

  observeEvent(input$trigger1, trigger1(trigger1()+1))

  observeEvent({trigger2(); trigger1()}, print('hello'), ignoreInit = T)

}

我仍然想了解为什么尝试 1-3 不起作用,所以如果有人有任何见解,请发表回复。


说明:正如 MattB 指出的,actionButton 初始化为 0,fileInput 初始化为 NULL。 这意味着,只要表达式最后一行的输入值为 NULL,尝试 2 和 3 中的观察者的 eventExpr 将计算为 NULL。 链接帖子中示例的 eventExpr 由 numericInput 和 textInput 组成。 由于它们分别使用值 0 和 '' 进行初始化,因此 eventExpr 永远不会返回 NULL 并且观察者总是对两个输入做出响应,无论哪个首先更改。

默认情况下, observeEvent设置了ignoreNULL = TRUE 正如您正确怀疑的那样,虽然观察者会触发对{x;y}任何部分的更改,但只有当整个表达式的值不是 NULL 时才会这样做。 在这个例子中,只要y是 NULL,无论你对x做什么,观察者都不会触发。 这很容易通过设置ignoreNULL = FALSE来解决。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM