你如何制作包含闪亮反应函数()的函数?

How do you make functions that wrap up Shiny reactive functions()?

我正在开发一个包含大量 "boiler plate" 闪亮输入和输出对象的包,并将它们包装在一个函数中。这个想法是为了快速启动应用程序而牺牲一些定制。

例如:

函数来源或包中

AuthMenuMacro <- function(input, session, code){

  …other observe functions that update menus….

  …other output functions that output plots, data tables….

  AuthToken <- reactive({

    token <- getTokenFromCode(code)

  })

}

server.r

code <- createAuthenticationCode()

shinyServer(function(input, output, session)){

  AuthMenuMacro(input, output, code)

  output$API_plot <- renderPlot({

    ## error as can’t see function AuthToken() within AuthMenuMacro()
    data <- getAPIData(AuthToken())

    plot(data)

  }) 
}

反应函数 AuthToken() 在另一个函数中,我无法从封闭函数外部获取它的值。我收到各种错误报告,我无法使用反应性环境等

我尝试使用列表 return,但这给出了一个错误:

Error in .getReactiveEnvironment()$currentContext() : 
  Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)

尝试return通过列表

AuthMenuMacro <- function(input, session, code){

  …other observe functions that update menus….

  …other output functions that output plots, data tables….

  AuthToken <- reactive({

    token <- getTokenFromCode(code)

  })

  AuthTable <- reactive({

    table <- getTableFromCode(code)      

  })

  return(list(code=AuthToken(),
              table=AuthTable())

}

我也尝试过使用 <<- 和环境,以及 reactiveVariables() 但它似乎不起作用,但我可能语法错误。

如果在上面的示例中我将 AuthToken() 和其他函数放在 'auth.r' 中并使用以下方式获取它,我可以接近我想要的:

server.r

code <- createAuthenticationCode()

shinyServer(function(input, output, session)){

  source('auth.r', local=T)

  output$API_plot <- renderPlot({

    ## now works as AuthToken() in correct environment
    data <- getAPIData(AuthToken())

    plot(data)

  }) 
}

...但如果可能的话,我想要一种通过函数来​​帮助简化和更轻松地传递变量的方法。

编辑:回答如下,但为了澄清:

我 return 使用 Shiny 样式对象编辑列表,而不是将其视为普通 R 函数。

例如AccountCode() 错误,AccountCode 正确

AuthMenuMacro <- function(input, session, code){

  …other observe functions that update menus….

  …other output functions that output plots, data tables….

AuthToken <- reactive({

    token <- getTokenFromCode(code)

})

AuthTable <- reactive({

  table <- getTableFromCode(code)      

})

return(list(code=AuthToken,  ## not AuthToken() as you would in server.r
          table=AuthTable))  ## not AuthTable() as you would in server.r

}

server.r

auth <- AuthMenuMacro
token <- auth$code ## not auth$code()
table <- auth$table ## not auth$table()

您可以让第一个 server.r 工作,但我认为调用一个函数并让它向调用者的环境添加变量的品味真的很差。如果您只想在调用者的环境中提供一个反应式表达式,那么这个怎么样:

AuthMenuMacro <- function(input, session, code){
  …other observe functions that update menus….
  …other output functions that output plots, data tables….
  reactive({
    token <- getTokenFromCode(code)
  })
}

server.r:

code <- createAuthenticationCode()

shinyServer(function(input, output, session)){
  AuthToken <- AuthMenuMacro(input, output, code)
  output$API_plot <- renderPlot({
    ## error as can’t see function AuthToken() within AuthMenuMacro()
    data <- getAPIData(AuthToken())
    plot(data)
  }) 
}

如果您对 return 有多个反应式表达式,则让 AuthMenuMacro return 一个命名列表,其值都是反应式表达式。例如:

code <- createAuthenticationCode()

shinyServer(function(input, output, session)){
  auth <- AuthMenuMacro(input, output, code)
  output$API_plot <- renderPlot({
    ## error as can’t see function AuthToken() within AuthMenuMacro()
    data <- getAPIData(auth$AuthToken())
    plot(data)
  })
  observe({
    cat("Auth info:", auth$AuthInfo(), "\n")
  })
}