Sharing app state between modules
Marcin Dubel�Staff Engineer
Sharing app state between modules
Why?
Table of content
Classics recap
Modularizing Shiny app code
# module
counterButton <- function(id, label = "Counter") {
ns <- NS(id)
tagList(
actionButton(ns("button"), label = label),
verbatimTextOutput(ns("out"))
)
}
counterServer <- function(id) {
moduleServer(
id,
function(input, output, session) {
count <- reactiveVal(0)
observeEvent(input$button, {
count(count() + 1)
})
output$out <- renderText({
count()
})
count
}
)
}
# app
ui <- fluidPage(
counterButton("counter1", "Counter #1"),
)
server <- function(input, output, session) {
counterServer("counter1")
}
shinyApp(ui, server)
# module
counterButton <- function(id, label = "Counter") {
ns <- NS(id)
tagList(
actionButton(ns("button"), label = label),
verbatimTextOutput(ns("out"))
)
}
counterServer <- function(id) {
moduleServer(
id,
function(input, output, session) {
count <- reactiveVal(0)
observeEvent(input$button, {
count(count() + 1)
})
output$out <- renderText({
count()
})
count
}
)
}
# app
ui <- fluidPage(
counterButton("counter1", "Counter #1"),
)
server <- function(input, output, session) {
counterServer("counter1")
}
shinyApp(ui, server)
# app
ui <- fluidPage(
counterButton("counter1", "Counter #1"),
counterButton("counter2", "Counter #2")
)
server <- function(input, output, session) {
counterServer("counter1")
counterServer("counter2")
}
shinyApp(ui, server)
Modularizing Shiny app code
Functional approach
Communication between modules
Communication between modules
varselect_mod_server <- function(input, output, session) {
return(
list(
xvar = reactive({ input$xvar }),
yvar = reactive({ input$yvar })
)
)
}
server <- function(input, output, session) {
ames <- make_ames()
plot1vars <- varselect_mod_server("plot1_vars")
plot2vars <- varselect_mod_server("plot2_vars")
res <- scatterplot_mod_server(
"plots",
dataset = ames,
plot1vars = plot1vars,
plot2vars = plot2vars
)
}
scatterplot_server_mod <- function(input, output, session, dataset, plot1vars, plot2vars) {
plot1_obj <- reactive({
p <- scatter_sales(dataset, xvar = plot1vars$xvar(), yvar = plot1vars$yvar())
return(p)
})
plot2_obj <- reactive({
p <- scatter_sales(dataset, xvar = plot2vars$xvar(), yvar = plot2vars$yvar())
return(p)
})
output$plot1 <- renderPlot({
plot1_obj()
})
output$plot2 <- renderPlot({
plot2_obj()
})
}
Object “managers” oriented approach
Sharing application state
Sharing application state
State Manager 1
State Manager 2
# varselect
server <- function(id, variables) {
moduleServer(id, function(input, output, session) {
observeEvent(list(input$xvar, input$yvar), {�
variables$set_vars(input$xvar, input$yvar)�
variables$trigger_plot()
})
})
}
Variables <- R6::R6Class(
classname = "Variables",
public = list(
triggers = reactiveValues(plot = 0),
trigger_plot = function() {
self$triggers$plot <- self$triggers$plot + 1
},
varX = NULL,
varY = NULL,
set_vars = function(varX, varY) {
self$varX <- varX
self$varY <- varY
}
)
)
# main
server <- function(id) {
moduleServer(id, function(input, output, session) {
Variables1 <- Variables$new()
varselect$server("plot1_vars", Variables1)
scatterplot$server("plot1", Variables1)
Variables2 <- Variables$new()
varselect$server("plot2_vars", Variables2)
scatterplot$server("plot2", Variables2)
})
}
# scatterplot
server <- function(id, variables) {
moduleServer(id, function(input, output, session) {
[...]
output$plot <- renderPlot({
variables$triggers$plot
scatter_sales(� dataset,� xvar = variables$varX,� yvar = variables$varY
)
})
})
}
Note! It is NOT global reactiveValues solution!
# server
r_global <- reactiveValues()
…
schedule_server("schedule", r_global)
place_server("place", r_global)
accommodation_server("accommodation", r_global)
covid_server("covid", r_global)
witnesses_server("witnesses", r_global)
preparations_server("preparations", r_global)
Benefits come with scale.
And scale will come.
Database�Manager
Data�Manager
User�Manager
Validation�Manager
[...]�Manager
State�Manager
Usual suspects:
Database�Manager
Data�Manager
User�Manager
Validation�Manager
Data�Manager
State�Manager
Thank you!
Marcin Dubel�Staff Engineer