2017-06-20 23 views
0

Shiny正在執行第一次加載時在其他標籤中使用的函數。舉一個最簡單的例子,看看從wch here採用的以下應用程序。這個應用程序有兩個菜單項。如果您單擊邊欄菜單項A,它應該執行renderUI函數,該函數將通過output$A_panel生成一個菜單項。這個應用程序完美。但是,如果您查看R控制檯,則會看到打印了Inside A PanelInside B Panel。這意味着當應用程序第一次加載時,renderUI函數都會被執行,除非用戶單擊菜單項B,否則閃亮只是隱藏它們。閃亮 - 不同標籤的功能在第一次加載時執行

我有一個應用程序使用類似的技術,但執行的函數使用SQL查詢和一些計算我不想在第一次加載時執行此操作。這嚴重拖慢了我的應用程序。有什麼辦法可以防止這種自動執行嗎?

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) 

回答

1

ConditionalPanel控制UI的可見性,而不是執行。 在這種情況下的快速解決方法是從基於sidebarmenu的值的函數中退出,如下所示。
在實現中,僅在菜單爲「b」時執行「b」輸出的renderUI

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) 

然而,在這個實現的計算中進行每次切換菜單時,因爲sidebarmenu變化觸發renderUI。 這可能不是您想要的,因爲您在加載菜單「b」時擔心要求高的計算。您可能希望僅在選擇「b」菜單後進行計算,但不會再次進行。

要做到這一點,您可以讓應用程序記住,如果outputB已被渲染或不使用reactiveValues,並且終止renderUI(如果它已被渲染)。 在下面的實現中,您將只看到一次打印的消息。

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

優秀的答案。我確實嘗試了一個變種if(input $ sidebarmenu!=「a」)return()'。這對我沒有用。但我在一個非常老的閃亮版本。我現在會責怪那個。 +1爲第二種方法。 – Sal

相關問題