2017-06-20 1 views
0

Shiny führt Funktionen aus, die beim ersten Laden in anderen Registerkarten verwendet werden. Für ein minimales Beispiel schauen Sie sich die folgende App an, die von wch here übernommen wurde. Es gibt zwei Menüpunkte in dieser App. Wenn Sie auf den Menüeintrag A der Seitenleiste klicken, sollte eine renderUI-Funktion ausgeführt werden, die über output$A_panel einen Menüeintrag erzeugt. Diese App macht es perfekt. Wenn Sie sich jedoch Ihre R-Konsole ansehen, sehen Sie, dass sowohl Inside A Panel als auch Inside B Panel gedruckt werden. Dies bedeutet, dass beide renderUI Funktion ausgeführt wurde, wenn die App zum ersten Mal geladen wird und glänzend sie nur versteckt, wenn der Benutzer auf Menüpunkt B klickt.shiny - Funktion für verschiedene Registerkarten wird beim ersten Laden ausgeführt

Ich habe eine App, die ähnliche Technik verwendet, aber die ausgeführten Funktionen verwenden SQL-Abfragen und einige Berechnungen was ich bei der ersten Ladung nicht machen möchte. Es verlangsamt meine App kritisch. Gibt es eine Möglichkeit, diese automatische Ausführung zu verhindern?

library(shiny) 
library(shinydashboard) 

ui <- dashboardPage(
     dashboardHeader(), 
     dashboardSidebar(
sidebarMenu(id = "sidebarmenu", 
      menuItem("A", tabName = "a", icon = icon("group", lib="font-awesome")), 
      menuItem("B", tabName = "b", icon = icon("check-circle", lib = "font-awesome")), 
      conditionalPanel("input.sidebarmenu === 'a'", 
          uiOutput('A_panel') 
          ), 
      conditionalPanel("input.sidebarmenu === 'b'", 
          uiOutput('B_panel') 
          ) 
), 
sliderInput("x", "Outside of menu", 1, 100, 50) 
), 
dashboardBody() 
) 

server <- function(input, output) { 

output$A_panel <- renderUI({ 
     cat('Inside A Panel \n') 
     sliderInput("b", "Under A", 1, 100, 50) 
}) 
output$B_panel <- renderUI({ 
     cat('Inside B Panel \n') 
     sliderInput("b", "Under B", 1, 100, 50) 
     }) 

} 
shinyApp(ui, server) 

Antwort

1

ConditionalPanel steuert die Sichtbarkeit der UI, nicht die Ausführung. Eine schnelle Lösung in diesem Fall ist, aus der Funktion basierend auf dem Wert sidebarmenu wie folgt herauszukommen.
In der Implementierung wird die renderUI für "b" -Ausgabe nur ausgeführt, wenn das Menü "b" ist.

library(shiny) 
library(shinydashboard) 

ui <- dashboardPage(
    dashboardHeader(), 
    dashboardSidebar(
    sidebarMenu(id = "sidebarmenu", 
       menuItem("A", tabName = "a", icon = icon("group", lib="font-awesome")), 
       menuItem("B", tabName = "b", icon = icon("check-circle", lib = "font-awesome")), 
       conditionalPanel("input.sidebarmenu == 'a'", 
           uiOutput('A_panel') 
       ), 
       conditionalPanel("input.sidebarmenu == 'b'", 
           uiOutput('B_panel') 
       ) 
    ), 
    sliderInput("x", "Outside of menu", 1, 100, 50) 
), 
    dashboardBody() 
) 

server <- function(input, output) { 

    output$A_panel <- renderUI({ 
    if(input$sidebarmenu != "a") return() 
    cat('Inside A Panel \n') 
    sliderInput("b", "Under A", 1, 100, 50) 
    }) 
    output$B_panel <- renderUI({ 
    if(input$sidebarmenu != "b") return() 
    cat('Inside B Panel \n') 
    sliderInput("b", "Under B", 1, 100, 50) 
    }) 

} 
shinyApp(ui, server) 

jedoch in dieser Implementierung wird die Berechnung jedes Mal, wenn Sie das Menü umschalten durchgeführt, da die Änderung in sidebarmenu die renderUI auslöst. Dies ist möglicherweise nicht genau das, was Sie wollen, da Sie sich beim Laden des Menüs "b" mit der anspruchsvollen Berechnung befassen müssen. Möglicherweise möchten Sie, dass die Berechnung erst nach Auswahl des "b" -Menüs erfolgt, aber nie wieder.

Um dies zu tun, können Sie die App merken lassen, ob der outputB gerendert wurde oder nicht reactiveValues verwendet, und renderUI beenden, wenn es bereits gerendert wurde. In der folgenden Implementierung sehen Sie die Nachricht nur einmal gedruckt.

library(shiny) 
library(shinydashboard) 

ui <- dashboardPage(
    dashboardHeader(), 
    dashboardSidebar(
    sidebarMenu(id = "sidebarmenu", 
       menuItem("A", tabName = "a", icon = icon("group", lib="font-awesome")), 
       menuItem("B", tabName = "b", icon = icon("check-circle", lib = "font-awesome")), 
       conditionalPanel("input.sidebarmenu == 'a'", 
           uiOutput('A_panel') 
       ), 
       conditionalPanel("input.sidebarmenu == 'b'", 
           uiOutput('B_panel') 
       ) 
    ), 
    sliderInput("x", "Outside of menu", 1, 100, 50) 
), 
    dashboardBody() 
) 

server <- function(input, output) { 

    RV <- reactiveValues(b_ui_flg=FALSE) 

    output$A_panel <- renderUI({ 
    if(input$sidebarmenu != "a") return() 
    cat('Inside A Panel \n') 
    sliderInput("b", "Under A", 1, 100, 50) 
    }) 

    observeEvent(input$sidebarmenu, { 
    if(input$sidebarmenu != "b") return() 
    if (RV$b_ui_flg) return() 
    RV$b_ui_flg <- TRUE 
    cat('Inside B Panel \n') 
    output$B_panel <- renderUI({ 
     sliderInput("b", "Under B", 1, 100, 50) 
    }) 
    }) 

} 
shinyApp(ui, server) 
+0

Ausgezeichnete Antwort. Ich habe eine Variante von 'if (input $ sidebarmenu! =" A ") return()' versucht. Das hat bei mir nicht funktioniert. Aber ich war auf einer sehr alten glänzenden Version. Ich werde das jetzt vorwerfen. +1 für den zweiten Ansatz. – Sal

Verwandte Themen