มันเงา - ฟังก์ชั่นสำหรับแท็บต่างๆ จะถูกดำเนินการเมื่อโหลดครั้งแรก

Shiny กำลังเรียกใช้ฟังก์ชันที่ใช้ในแท็บอื่นเมื่อโหลดครั้งแรก สำหรับตัวอย่างเล็กๆ น้อยๆ ให้ดูที่แอปต่อไปนี้ซึ่งนำมาใช้จาก ที่นี่. แอพนี้มีสองรายการเมนู หากคุณคลิกที่รายการเมนูแถบด้านข้าง A มันควรจะเรียกใช้ฟังก์ชัน renderUI ซึ่งจะสร้างรายการเมนูผ่าน output$A_panel แอพนี้ทำได้อย่างสมบูรณ์แบบ อย่างไรก็ตาม หากคุณดูที่คอนโซล R ของคุณ คุณจะเห็นทั้ง Inside A Panel และ Inside 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)

person Sal    schedule 20.06.2017    source แหล่งที่มา


คำตอบ (1)


ConditionalPanel ควบคุมการมองเห็น UI ไม่ใช่การดำเนินการ การแก้ไขด่วนในกรณีนี้คือการออกจากฟังก์ชันตามค่า sidebarmenu ดังด้านล่าง
ในการใช้งาน เอาต์พุต renderUI สำหรับ "b" จะถูกดำเนินการเมื่อเมนูเป็น "b" เท่านั้น

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" เท่านั้น แต่จะไม่ทำอีกต่อไป

ในการดำเนินการดังกล่าว คุณสามารถปล่อยให้แอปจดจำได้ว่าเอาต์พุต B ได้รับการเรนเดอร์แล้วหรือไม่ใช้ 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)
person Kota Mori    schedule 20.06.2017
comment
คำตอบที่ยอดเยี่ยม ฉันลองใช้รูปแบบ ` if(input$sidebarmenu != a) return()` แล้ว นั่นไม่ได้ผลสำหรับฉัน แต่ฉันอยู่ในเวอร์ชันมันวาวที่เก่ามาก ฉันจะตำหนิสิ่งนั้นในตอนนี้ +1 สำหรับแนวทางที่สอง - person Sal; 21.06.2017