Module that accepts a parameter that is either reactive or not

I'm wondering if other people also run into this sometimes and wanted to see others' thoughts.

Sometimes when creating a shiny module, one of the input parameters to the server function can be either a reactive expression or just a regular variable. The proper way to deal with that is to accept a reactive in the module, and the code that calls the module should send in a reactive. If the caller has a regular variable instead of a reactive, it can be wrapped inside a reactive(...) call.

Sometimes I have a parameter that will usually be a normal variable, but it could be reactive. Instead of forcing the caller to always wrap it inside reactive(), I get tempted to write code in the module that will simply turn a non-reactive into a reactive.

Is that something other people do? Do you think it's a terrible idea to not be 100% strict about the type of input?

Example of what I get tempted to do (but haven't actually done because I can't decide if it's ok):

#' @param user_id Either an integer or a reactive expression returning an integer
my_module <- function(input, output, session, user_id) {
  if (!is.reactive(user_id)) user_id <- reactive(user_id)
}

We do that in Shiny but instead of is.reactive, we do is.function and function() { value }.

Does everything going into a server side module have to be coerced into a reactive? I was having trouble setting one up to take in a non-reactive dataset with a variable to filter it, like so:

my_module <- function(input, output, session, non_reactive_data, filter_variable) {

   filtered_data <- reactive({
      non_reactive_data %>% filter(variable == filter_variable)
   })

}

Would this be solved by having reactive(non_reactive_data) as the function argument?

Haven't thought of that.

  • Is there a great advantage to making it a function instead of a reactive? Is it simply to reduce the number of reactives and slightly simplify the reactive graph?

  • Won't that not work in some cases, for example if you have an observeEvent that expect a reactive or other cases that I can't think of? Or is it supposed to be a good solution for that in general

No, not all module parameters have to be reactive

Like Dean said, there's no issue at all with non-reactive arguments in the module server function (reactive arguments in modules are just a very common and useful pattern).

For example, if you look at http://shiny.rstudio.com/gallery/module-example.html and copy-paste the module and the app.R files, you can see that non-reactives work fine by changing the cols argument in scatterPlot from left() to left (and from right() to right):

output$plot1 <- renderPlot({
  scatterPlot(dataWithSelection(), left)
})
  
output$plot2 <- renderPlot({
  scatterPlot(dataWithSelection(), right)
})

AND by changing the call to callModule in the app.R's server function from left = reactive(c("cty", "hwy")) to simply left = c("cty", "hwy") (and similarly for right):

df <- callModule(linkedScatter, "scatters", reactive(mpg),
  left = c("cty", "hwy"),
  right = c("drv", "hwy")
)

So, this wasn't the problem you were experiencing in your app...

1 Like