我在一个巨大的应用程序中遇到了观察者和模块的问题。我创建了一个较小的示例。
我想做的事:
在其中一个可视化(选项卡之一)中,我使用传单作为位置选择器。最初进展顺利:选择一个区域 --> 按该区域过滤数据并以模式显示。
如果我更改了上一个选择菜单中的任何内容(第 4 步),但是我会遇到反应性问题。每次点击 1 次更改 = 1 个模态。 n 个更改 = n 个模态弹出,导致系统崩溃。该问题是由最后一个选择模块中的反应性问题引起的。我通过向该模块添加模态来将问题定位到该模块。这就是示例中所示的内容。
每当我更改此模块时,就会出现问题。
下面是我创建的片段:每当我更改选项卡时,它都会显示模式。将其更改为观察也没有帮助。当 input$tab 更改时,如何更改额外的选择,但确保不会创建额外的观察者?
现在:选项卡中的每个更改都会创建一个额外的观察者,选择中的每个更改都会为传单地图等创建一个额外的观察者。
# Load necessary libraries
library(shiny)
library(dplyr)
# Define the UI for the selections module
# This function creates a select input with multiple selection enabled
selectionsUI <- function(id) {
ns <- NS(id)
selectInput(ns("variableSelect"), "Choose some:", choices = c("X", "Z"), multiple = TRUE)
}
# Define the server logic for the selections module
# This function returns the selected variables from the select input
selectionsServer <- function(id) {
moduleServer(id, function(input, output, session) {
reactive({
input$variableSelect
})
})
}
# Define the UI for the last selections module
# This function creates a button and an output UI element
lastSelectionsUI <- function(id) {
ns <- NS(id)
tagList(
actionButton(ns("infoButton"), "INFORMATION BUG"),
uiOutput(ns("lastSelector"))
)
}
# Define the server logic for the last selections module
# This function shows a modal when the button is clicked and updates the last filter based on the selected tab
lastSelectionsServer <- function(id, selectionsSnapshot, selectedTab) {
moduleServer(id, function(input, output, session) {
lastFilter <- reactiveVal(NULL)
observeEvent(input$infoButton, {
showModal(
modalDialog(
title = "This is not working??",
paste0("Selected tab: ", selectedTab)
)
)
})
output$lastSelector <- renderUI({
ns <- session$ns
if (selectedTab == "Y below zero") {
tagList(
selectInput(label = "LAST FILTER", ns("filterAgain"), choices = selectionsSnapshot(), multiple = TRUE)
)
} else {
tagList()
}
})
observe({
lastFilter(input$filterAgain)
print(lastFilter())
})
return(lastFilter)
})
}
# Define the UI for the test module
# This function creates a layout with two columns and a tabset panel
testUI <- function(id) {
ns <- NS(id)
tagList(
column(2, uiOutput(ns("lastSelections"))),
column(6, tabsetPanel(
id = ns("tab"),
tabPanel("Y above zero", uiOutput("Y_above_zero")),
tabPanel("Y below zero", uiOutput(ns("Y_below_zero"))),
))
)
}
# Define the server logic for the test module
# This function creates a reactive expression that filters data based on the selected tab and the last filter
testServer <- function(id, data, selectionsSnapshot) {
moduleServer(id, function(input, output, session) {
output$lastSelections <- renderUI({
ns <- session$ns
lastSelectionsUI(ns("last"))
})
lastFilter <- reactiveVal(NULL)
observeEvent(input$tab, {
print("working")
myFilter <- lastSelectionsServer("last", selectionsSnapshot, input$tab)
lastFilter(myFilter)
})
observe({
print("*****")
print(lastFilter())
print("******")
})
# Create a reactive expression that filters data based on the selected tab and the last filter
filteredData <- reactive({
df <- data()
if (input$tab == "Y above zero") {
df <- df[df$Y > 0, ]
} else if (input$tab == "Y below zero") {
df <- df[df$Y <= 0, ]
}
# Filter based on the last filter
if (!is.null(lastFilter())) {
filterValue <- lastFilter()()
df <- df %>% select(all_of(filterValue))
}
df
})
# Add an action button to the UI for each tab
output$Y_above_zero <- renderUI({
if (input$tab == "Y above zero") {
actionButton(ns("showDataAbove"), "Show Data")
}
})
output$Y_below_zero <- renderUI({
if (input$tab == "Y below zero") {
ns <- session$ns
actionButton(ns("showDataBelow"), "Show Data")
}
})
# Show the filtered data in a modal when the button is clicked
observeEvent(input$showDataAbove, {
showModal(modalDialog(
title = "Data where Y is above zero",
renderTable(filteredData())
))
})
observeEvent(input$showDataBelow, {
showModal(modalDialog(
title = "Data where Y is below zero",
renderTable(filteredData())
))
})
})
}
# Define the main page UI
# This function creates a layout with a main filter, an intermediate filter, and a test module
mainPageUI <- function(id) {
ns <- NS(id)
fluidPage(
h1("Main filter"),
selectionsUI(ns("selections")),
actionButton(ns("getData"), "Get data from database"),
tags$hr(),
tags$br(),
h1("Intermediate on-the-fly filter"),
radioButtons(ns("testFilter"), "Filter data", choices = c("X Above zero", "X Below zero")),
tags$hr(),
tags$br(),
wellPanel(fluidRow(testUI(ns("test"))))
)
}
# Define the main page server
# This function gets data from a database and starts the test server when the test filter is changed
mainPageServer <- function(id) {
moduleServer(id, function(input, output, session) {
selections <- selectionsServer("selections")
observeEvent(input$getData, {
req(selections)
print("Getting data from database")
# Save a snapshot of the selections
selectionsSnapshot <- reactiveVal(selections())
# Get some data from a database
data <- reactive({
data.frame(X = rnorm(10), Y = rnorm(10), Z = rnorm(10))
})
print("Got data from database")
observeEvent(input$testFilter, {
# Filter the initial data on the fly
filteredData <- reactive({
if (input$testFilter == "X Above zero") {
data()[data()$X > 0, ]
} else {
data()[data()$X <= 0, ]
}
})
# Start the test server inside of this observeEvent
testServer("test", filteredData, selectionsSnapshot)
})
})
})
}
# Define the shiny server
server <- shinyServer(function(global, input, output, session) {
observe({
mainPageServer(("main_page"))
})
})
# Define the shiny UI
ui <- fluidPage(mainPageUI("main_page"))
# Run the application
shinyApp(ui = ui, server = server)
您在两个服务器模块中的
ns <- session$ns
中有 renderUI
。你可以把它们放在外面。接下来,您将在观察者内部定义响应式对象。在这种情况下您可以使用 eventReactive
。试试这个
# Load necessary libraries
library(shiny)
library(dplyr)
# Define the UI for the selections module
# This function creates a select input with multiple selection enabled
selectionsUI <- function(id) {
ns <- NS(id)
selectInput(ns("variableSelect"), "Choose some:", choices = c("X", "Z"), multiple = TRUE)
}
# Define the server logic for the selections module
# This function returns the selected variables from the select input
selectionsServer <- function(id) {
moduleServer(id, function(input, output, session) {
reactive({
input$variableSelect
})
})
}
# Define the UI for the last selections module
# This function creates a button and an output UI element
lastSelectionsUI <- function(id) {
ns <- NS(id)
tagList(
actionButton(ns("infoButton"), "INFORMATION BUG"),
uiOutput(ns("lastSelector"))
)
}
# Define the server logic for the last selections module
# This function shows a modal when the button is clicked and updates the last filter based on the selected tab
lastSelectionsServer <- function(id, selectionsSnapshot, selectedTab) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
lastFilter <- reactiveVal(NULL)
observeEvent(input$infoButton, {
showModal(
modalDialog(
title = "This is not working??",
paste0("Selected tab: ", selectedTab)
)
)
})
output$lastSelector <- renderUI({
if (selectedTab == "Y below zero") {
tagList(
selectInput(label = "LAST FILTER", ns("filterAgain"), choices = selectionsSnapshot(), multiple = TRUE)
)
} else {
tagList()
}
})
observe({
lastFilter(input$filterAgain)
print(lastFilter())
})
return(lastFilter)
})
}
# Define the UI for the test module
# This function creates a layout with two columns and a tabset panel
testUI <- function(id) {
ns <- NS(id)
tagList(
column(2, uiOutput(ns("lastSelections"))),
column(6, tabsetPanel(
id = ns("tab"),
tabPanel("Y above zero", uiOutput("Y_above_zero")),
tabPanel("Y below zero", uiOutput(ns("Y_below_zero"))),
))
)
}
# Define the server logic for the test module
# This function creates a reactive expression that filters data based on the selected tab and the last filter
testServer <- function(id, data, selectionsSnapshot) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
output$lastSelections <- renderUI({
# ns <- session$ns
lastSelectionsUI(ns("last"))
})
lastFilter <- reactiveVal(NULL)
observeEvent(input$tab, {
print("working")
myFilter <- lastSelectionsServer("last", selectionsSnapshot, input$tab)
lastFilter(myFilter)
})
observe({
print("*****")
print(lastFilter())
print("******")
})
# Create a reactive expression that filters data based on the selected tab and the last filter
filteredData <- reactive({
df <- data()
if (input$tab == "Y above zero") {
df <- df[df$Y > 0, ]
} else if (input$tab == "Y below zero") {
df <- df[df$Y <= 0, ]
}
# Filter based on the last filter
if (!is.null(lastFilter())) {
filterValue <- lastFilter()()
df <- df %>% select(all_of(filterValue))
}
df
})
# Add an action button to the UI for each tab
output$Y_above_zero <- renderUI({
if (input$tab == "Y above zero") {
actionButton(ns("showDataAbove"), "Show Data")
}
})
output$Y_below_zero <- renderUI({
if (input$tab == "Y below zero") {
ns <- session$ns
actionButton(ns("showDataBelow"), "Show Data")
}
})
# Show the filtered data in a modal when the button is clicked
observeEvent(input$showDataAbove, {
showModal(modalDialog(
title = "Data where Y is above zero",
renderTable(filteredData())
))
})
observeEvent(input$showDataBelow, {
showModal(modalDialog(
title = "Data where Y is below zero",
renderTable(filteredData())
))
})
})
}
# Define the main page UI
# This function creates a layout with a main filter, an intermediate filter, and a test module
mainPageUI <- function(id) {
ns <- NS(id)
fluidPage(
h1("Main filter"),
selectionsUI(ns("selections")),
actionButton(ns("getData"), "Get data from database"),
tags$hr(),
tags$br(),
h1("Intermediate on-the-fly filter"),
radioButtons(ns("testFilter"), "Filter data", choices = c("X Above zero", "X Below zero")),
tags$hr(),
tags$br(),
wellPanel(fluidRow(testUI(ns("test"))))
)
}
# Define the main page server
# This function gets data from a database and starts the test server when the test filter is changed
mainPageServer <- function(id) {
moduleServer(id, function(input, output, session) {
selections <- selectionsServer("selections")
# observeEvent(input$getData, {
# req(selections())
print("Getting data from database")
# Save a snapshot of the selections
selectionsSnapshot <- reactiveVal(selections())
# Get some data from a database
data <- eventReactive(input$getData, {
data.frame(X = rnorm(10), Y = rnorm(10), Z = rnorm(10))
})
print("Got data from database")
# observeEvent(input$testFilter, {
# Filter the initial data on the fly
filteredData <- eventReactive(input$testFilter, {
req(data())
if (input$testFilter == "X Above zero") {
data()[data()$X > 0, ]
} else {
data()[data()$X <= 0, ]
}
})
# Start the test server inside of this observeEvent
testServer("test", filteredData, selectionsSnapshot)
# })
# })
})
}
# Define the shiny server
server <- shinyServer(function(global, input, output, session) {
observe({
mainPageServer(("main_page"))
})
})
# Define the shiny UI
ui <- fluidPage(mainPageUI("main_page"))
# Run the application
shinyApp(ui = ui, server = server)