【问题标题】:Make shiny app modules share reactive values with each other使闪亮的应用程序模块彼此共享反应值
【发布时间】:2021-01-14 21:58:21
【问题描述】:

我正在尝试模块化一个闪亮的应用程序。到目前为止,它运行得很顺利,但是我在设计具有两个模块 A 和 B 的系统时遇到了麻烦,其中 A 需要来自 B 的数据,而 B 需要来自 A 的数据。

首先,按照this tutorial(闪亮版本 1.5),我得到了这个非常基本的自包含示例。

library(shiny)

#######################
#     FILE MODULE     #
# Load and save value #
#######################
fileModuleUI <- function(id) {
  ns <- NS(id)

  tagList(
    fileInput(ns("fileInput"), "Input"),
    downloadButton(ns("fileOutput"), "Save problem")
  )
}

fileModuleServer <- function(id, textFieldData) {
  moduleServer(
    id,
    function(input, output, session) {

      # Write observer
      output$fileOutput <- downloadHandler(
        filename = function() { "myfile.dcf" },
        content = function(file) { dput(textFieldData(), file) }
      )

      # Read observers
      userFile <- reactive({
        validate(need(input$fileInput, message = FALSE))
        input$fileInput
      })

      fileContent <- reactive({
        dget(userFile()$datapath)
      })

      return(fileContent)
    }
  )
}

###############
#   MAIN UI   #
###############
ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(fileModuleUI("dataHandler")),
    mainPanel(textInput("mainData", label = "Type your data in here"))
  )
)

server <- function(input, output, session) {
  fileContent <- fileModuleServer("dataHandler", reactive(input$mainData))

  observe({
    updateTextInput(session, "mainData", value = fileContent())
  })
}

shinyApp(ui = ui, server = server)

使用这个漂亮的工具,我可以从textInput 中加载一行文本并将其保存在一个文件中。

现在我还想模块化我的mainPanel 中的内容。我们就叫它mainModule吧。

虽然构建mainModuleUI 很简单,但mainModuleServer 引入了一些交叉依赖问题:

  • fileModuleServer 需要知道 mainModuleServer 的文本字段,以便将其值保存在文件中
  • mainModuleServer 需要知道来自 fileModuleServer 的文件内容,以便在加载文件时更新其文本输入字段

因此,服务器可能看起来像这样:

fileModuleServer <- function(id, textFieldData) { ... }
mainModuleServer <- function(id, fileContent) { ... }

server <- function(input, output, session) {
  # what to pass as second parameter?
  fileContent <- fileModuleServer("dataHandler", ???)

  # would passing fileContent even work?
  mainModuleServer("mainPanel", fileContent)
}

有什么好的方法可以解决这个问题?

【问题讨论】:

    标签: r shiny module


    【解决方案1】:

    我通过在我的主应用程序中引入 reactiveValue 来实现它。然后我将该值传递给我的服务器,并通过写入value('this is some new value') 更改其值或通过调用value() 读取其值。

    这可能看起来像这样:

    # Module A
    moduleAServer <- function(id, someData) {
      moduleServer(
        id,
        function(input, output, session) {
          # when clicking on load-button, just pretend to load some data
          observeEvent(input$load, {
            someData('This is the new data!')
          })
    
          observeEvent(input$save, {
            print(paste('Saving the following:', someData()))
          })
        }
      )
    }
    
    # Module B
    moduleBServer <- function(id, someData) {
      moduleServer(
        id,
        function(input, output, session) {
          # observe will be called when Module A changes the data inside someData
          observe({
            # not sure if I need this req
            req(someData)
            print(paste('some Data changed to', someData()))
          })
        }
      )
    }
    
    mainServer <- function(input, output, session) {
      someData <- reactiveVal('oh')
      chosenFile <- moduleAServer('filePanel', someData)
      inputServer <- moduleBServer('mainPanel', someData)
    }
    

    【讨论】:

      猜你喜欢
      • 2020-03-12
      • 2019-09-01
      • 2020-05-17
      • 2017-03-10
      • 2017-12-11
      • 1970-01-01
      • 2018-07-09
      • 2017-07-27
      • 2020-10-13
      相关资源
      最近更新 更多