rshinydynamic-ui

Is there a way to make a Dynamic UI with Images of RShiny load faster?


I have a dynamic UI that loads a card item and its description, and for 1 page I make a 50 cards displayed (as default) or else the remainder of the cards in last page (which is defined from num_cards() reactive values) this is the dynamic UI code:

output$dynamicUI <- renderUI({
    do.call(tagList, lapply(1:num_cards(), function(i) {
        fluidRow(
          column(width = 3,
                 style = "padding: 0; margin: 0;",  # Zero margin and padding
                 box(
                   uiOutput(paste0("dynamicImage", i))
                 )
          ),
          column(width = 9,
                 style = "padding: 0; margin: 0;",  # Zero margin and padding
                 fluidRow(
                   # Row 1 (top)
                   column(width = 9,
                          style = "padding: 0; margin: 0; font-size: 36px; font-family: 'Berlin Sans FB', Demi; background: transparent;",  # Zero margin and padding
                          box(
                            width = 12,
                            textOutput(paste0("cardName", i))
                          )
                   ),
                   column(width = 3,
                          style = "padding: 0; margin: 0; font-alignment: 'right'; font-size: 18px; font-family: 'Times New Roman', serif; background: transparent; text-align: right !important;",  # Zero margin and padding
                          box(
                            width = 10,
                            textOutput(paste0("releaseDate", i))
                          )
                   )
                 ),
                 fluidRow(class = "custom-fluid-row",
                          # Row 2 (middle)
                          column(
                            width = 2,
                            div(
                              imageOutput(paste0("BOXICONONE", i)) %>% tagAppendAttributes(class = 'BOXICONONE'),
                              div(
                                textOutput(paste0("BOXONE", i)) %>% tagAppendAttributes(class = 'BOXONE')
                              )
                            )
                          ),
                          column(
                            width = 2,
                            div(
                              imageOutput(paste0("BOXICONTWO", i)) %>% tagAppendAttributes(class = 'BOXICONTWO'),
                              div(
                                textOutput(paste0("BOXTWO", i)) %>% tagAppendAttributes(class = 'BOXTWO')
                              )
                            )
                          ),
                          column(
                            width = 2,
                            div(
                              imageOutput(paste0("BOXICONTHREE", i)) %>% tagAppendAttributes(class = 'BOXICONTHREE'),
                              div(
                                textOutput(paste0("BOXTHREE", i)) %>% tagAppendAttributes(class = 'BOXTHREE')
                              )
                            )
                          ),
                          column(
                            width = 2,
                            style = "padding: 0; margin: 0; font-size: 22px; font-family: 'Times New Roman', serif; background: transparent",  # Zero margin and padding
                            box(
                              width = 12,
                              textOutput(paste0("BOXFOUR", i)) %>% tagAppendAttributes(class = 'BOXFOUR')
                            )
                          ),
                          column(
                            width = 2,
                            style = "padding: 0; margin: 0; font-size: 22px; font-family: 'Times New Roman', serif; background: transparent",  # Zero margin and padding
                            box(
                              width = 12,
                              textOutput(paste0("BOXFIVE", i)) %>% tagAppendAttributes(class = 'BOXFIVE')
                            )
                          )
                 ),
                 fluidRow(class = "custom-fluid-row",
                          # Row 3 (bottom)
                          column(
                            height = 130,
                            width = 12,
                            style = "padding: 0; margin: 0; background: transparent; font-size: 18px; font-family: 'Times New Roman'",  # Zero margin and padding
                            box(
                              height = 130,
                              width = 12,
                              textOutput(paste0("cardDescription", i))
                            )
                          )
                 )
          )
        )
      }))
  })

Above are the main UI in my apps, and I have left sidebarmenu that when clicked, updates the dynamicUI accordingly to the menu category, but the loading for this UI is kinda slow, (I think because I use a lots of image displayed as the card image and its box icons). Here is the profvis results of some simulation

enter image description here

I was wondering if theres a way I can make the UI smoother or maybe make the renderUI/renderImage load image more faster.. I appreciate your help!

EDIT: These are the minimal reproducible example for the apps that i can create, I can`t make it more simpler than this, feel free to use

https://sendeyo.com/en/065bf146a6


Solution

  • I'm not willing to download from sendeyo... what is the slow or data heavy part of your cards ? is it image data ? the html standard includes a lazy load feature. Heres an example of 1000 lady loaded images thrown into a dynamic shiny ui. it seems highly performant. There is definitely a dip in perceived performance when removing the lazy option, but its still rather fast even without ...

    library(shiny)
    library(tidyverse)
    library(glue)
    ui <- fluidPage(
      uiOutput("dynimages")
    )
    
    server <- function(input, output, session) {
      output$dynimages <- renderUI({
        
        tagList(map(1:1000,
            \(x){tags$image( loading="lazy" ,
                             src=glue("https://picsum.photos/id/{x}/400/600"))}))
        
      })
    }
    
    shinyApp(ui, server)