New construct: a reactiveVal() that invalidates every time its value is set (even if the value hasn't changed)

When setting a shiny input value from JavaScript, we have the ability to set {priority: 'event'} so that even if the value is the same as the previous, shiny will still trigger the input as if it was invalidated.

Native reactive() can also invalidate despite their return value not changing - if anything inside of them is invalidated.

But there have been a few times where I ran into a case that was missing: I needed a reactiveVal()and I needed it to be able to invalidate every time the value is set, even if it hasn't changed.

I came up with an implementation, I'm wondering if the @shiny team (@winston @jcheng ) thinks this is ok. I'm not too happy with the fact that it uses internal undocumented "API", but other than that will this seem to work?

reactiveValEvent <- function(data = NULL) {
  rv <- shiny::reactiveVal(data)
  function(data) {
    if (missing(data)) {
      rv()
    } else {
      attr(rv, ".impl")$private$dependents$invalidate()
      rv(data)
    }
  }
}

You can test it with this app:

library(shiny)

ui <- fluidPage(
  numericInput("num", "num", 10),
  actionButton("set", "set")
)

server <- function(input, output, session) {
    myval <- reactiveValEvent(NULL)
    observeEvent(input$set, {
      myval(input$num)
    })
    observe({
        print(myval())
    })
}

shinyApp(ui, server)

If you change reactiveValEvent to reactiveVal, then the number will only print when it changes.

I'm not on board with accessing the private bits, but you can work around that by introducing a second reactiveVal:

reactiveValEvent <- function(data = NULL) {
  rv <- shiny::reactiveVal(data)
  rv_trigger <- shiny::reactiveVal(FALSE)
  function(data) {
    if (missing(data)) {
      rv_trigger() # Take a reactive dependency on rv_trigger
      return(rv())
    } else {
      rv_trigger(isolate(!rv_trigger())) # This should always result in rv_trigger invalidation
      rv(data)
    }
  }
}

But it'd be better still if reactiveVal() just had an ignoreDuplicate = TRUE parameter (i.e. you specify which behavior you want when creating the reactiveVal).

1 Like

That's a great modification, I was very unhappy with my version. I opened an issue on shiny to suggest this as a parameter for reactiveVal(). Thanks again Joe

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.