我正在阅读有关闪亮反应式编程的所有内容.我有点困惑.以下所有工作但首选方法是什么?为什么?显然,下面的示例很简单,但是在使用任何方法创建更大的应用程序时,我会遇到麻烦吗?
我一直倾向于倾向于服务器代码#1中的风格.原因是,我能够打破if语句.对我来说,这似乎更具可读性.同样,下面的简单示例并不是非常复杂,但您可以很容易地想象服务器代码2和服务器代码3如何通过大量嵌套的if/if else语句变得非常混乱.
UI代码
library(shiny)
ui <- fluidPage(
selectInput(inputId = 'choice',
label = 'Choice',
choice = c('Hello','Goodbye'),
selected = c('Hello')
),
textOutput('result')
)
Run Code Online (Sandbox Code Playgroud)
服务器代码1
server <- function(input,output,session)({
text <- reactiveValues()
observe({
if (input$choice == 'Hello') {
text$result <- 'Hi there'
}
})
observe({
if (input$choice == 'Goodbye') {
text$result <- 'See you later'
}
})
output$result <- renderText({
text$result
})
})
shinyApp(ui = ui, server = server)
Run Code Online (Sandbox Code Playgroud)
服务器代码2
server <- function(input,output,session)({
getStatus <- reactive({
if (input$choice == 'Hello') {
'Hi there'
} else if (input$choice == 'Goodbye'){
'See you later'
}
})
output$result <- renderText({
getStatus()
})
})
shinyApp(ui = ui, server = server)
Run Code Online (Sandbox Code Playgroud)
服务器代码3
server <- function(input,output,session)({
text <- reactiveValues()
observeEvent(input$choice,{
if (input$choice == 'Hello') {
text$result <- 'Hi there'
} else if (input$choice == 'Goodbye') {
text$result <- 'See you later'
}
})
output$result <- renderText({
text$result
})
})
shinyApp(ui = ui, server = server)
Run Code Online (Sandbox Code Playgroud)
Cha*_*abo 30
首先,这些东西有点含糊不清,在某些方面不是很直观,甚至在Shiny博客上也是如此!
以下是我对该主题的最佳理解..
让我们开始吧 reactive
反应函数允许用户监视输入或其他变化变量的状态,并返回要在代码中的其他地方使用的值.对反应变量的监视被认为是懒惰的,"反应式表达式使用惰性求值;也就是说,当它们的依赖性发生变化时,它们不会立即重新执行,而是等到其他人调用它们.(来源) ".您可以在示例2中很好地展示这一点,因为您可以在renderText环境中调用变量,一旦调用了响应调用内部的代码并重新计算变量.
对于科学书呆子来说,这很像量子力学,因为通过调用反应变量(观察它)会导致它通过重新评估而变化,过度延伸?
现在来 observe
观察是类似的反应,主要区别在于它不会将任何值返回到除其自身之外的任何其他环境,并且它不是懒惰的.observe函数会持续监视其环境中所有无功值的任何更改,并在更改这些值时在其环境中运行代码.因此,观察不是一种"懒惰"评估,因为它不会等待在重新评估之前被调用.再次注意,您无法从observe中分配变量.
为了实验:
server <- function(input,output,session)({
observe({
if (input$choice == 'Hello') {
getStatus <- 'Hi there'
}
})
observe({
if (input$choice == 'Goodbye') {
getStatus <- 'See you later'
}
})
output$result <- renderText({
getStatus
})
})
shinyApp(ui = ui, server = server)
Run Code Online (Sandbox Code Playgroud)
需要注意的是,在执行代码期间observe,我们可以操纵外部环境反应变量.在您的情况下,您text <- reactiveValues()通过调用分配,然后操纵它text$result <- 'Hi there'.我们也可以做更新selectInput选择或其他闪亮的小部件,但我们不能在这个环境中分配任何非反应变量,就像上面的例子中的getStatus一样.这个想法在observe文档中提到,
"观察者就像一个反应性表达,因为它可以读取反应值并调用反应式表达式,并在这些依赖性发生变化时自动重新执行.但与反应式表达式不同,它不会产生结果而不能用作其他反应式表达式的输入.因此,观察者只对其副作用有用(例如,执行I/O)(来源)"
最后, observeEvent
使用的最佳方法observeEvent是将其视为已定义的触发器,因为它会监视一个事件或更改变量,然后在事件发生时触发.我最常使用它来观察按钮的输入,因为这是一个定义的事件,我希望在按下按钮后发生事情.它使用的isolate环境我认为是这个功能如何工作的完美名称.
在这个环境中我们可以调用一堆反应变量,但我们只定义一个作为触发器.触发器之间的主要区别在于observeEvent,随时运行任何更改,并等待触发器.请注意,此环境类似于observe,因为它不返回非反应变量.observeobserveobserveEvent
摘要
这是一个将所有这些想法结合在一起的例子:
library(shiny)
ui<-
fluidPage(
fluidRow(
column(4,
h2("Reactive Test"),
textInput("Test_R","Test_R"),
textInput("Test_R2","Test_R2"),
textInput("Test_R3","Test_R3"),
tableOutput("React_Out")
),
column(4,
h2("Observe Test"),
textInput("Test","Test"),
textInput("Test2","Test2"),
textInput("Test3","Test3"),
tableOutput("Observe_Out")
),
column(4,
h2("Observe Event Test"),
textInput("Test_OE","Test_OE"),
textInput("Test_OE2","Test_OE2"),
textInput("Test_OE3","Test_OE3"),
tableOutput("Observe_Out_E"),
actionButton("Go","Test")
)
),
fluidRow(
column(8,
h4("Note that observe and reactive work very much the same on the surface,
it is when we get into the server where we see the differences, and how those
can be exploited for diffrent uses.")
))
)
server<-function(input,output,session){
# Create a reactive Evironment. Note that we can call the varaible outside same place
# where it was created by calling Reactive_Var(). When the varaible is called by
# renderTable is when it is evaluated. No real diffrence on the surface, all in the server.
Reactive_Var<-reactive({c(input$Test_R, input$Test_R2, input$Test_R3)})
output$React_Out<-renderTable({
Reactive_Var()
})
# Create an observe Evironment. Note that we cannot access the created "df" outside
# of the env. A, B,and C will update with any input into any of the three Text Feilds.
observe({
A<-input$Test
B<-input$Test2
C<-input$Test3
df<-c(A,B,C)
output$Observe_Out<-renderTable({df})
})
#We can change any input as much as we want, but the code wont run until the trigger
# input$Go is pressed.
observeEvent(input$Go, {
A<-input$Test_OE
B<-input$Test_OE2
C<-input$Test_OE3
df<-c(A,B,C)
output$Observe_Out_E<-renderTable({df})
})
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)
reactive
创建一个可以通过用户输入随时间更改的变量,仅在调用时评估"lazy"含义.
observe
持续监控反应事件和变量,只要在环境(观察到的环境)中更改任何反应变量,就会对代码进行评估.可以更改先前定义的反应变量的值,不能创建/返回变量.
observeEvent(Domino效果)持续监视一个定义的反应变量/事件(触发器),并在触发器通过该触发器的更改/输入激活时运行代码.可以更改先前定义的反应变量的值,不能创建/返回变量.
eventReactive 创建一个变量,其定义的触发器类似于observeEvent.当您需要由触发器而不是在调用触发器时进行评估的反应变量时,请使用此选项.
我希望这会有所帮助,如果我的理解错误或者有更多的澄清,请随时编辑这个答案.
已经有一个非常详细的答案,所以我只想加上我自己的短简单两分钱:
只要有可能,坚持reactive()而不是reactiveValues().Normal reactive()更符合闪亮的反应式编程哲学,这意味着reactive()表达式只是告诉闪亮如何计算变量,而不必指定何时.Shiny将负责确定何时计算它.它们将被懒惰地评估(仅在需要时),它们将缓存它们的值,它们将与书签功能一起使用 - 它只是闪亮的设计方式,应该始终是第一选择.
有了reactiveValues(),你现在又回到了更为迫切的编程领域,而不是被动反应.有些情况下reactive()不会削减它而你需要使用reactiveValues()(或reactiveVal()),但只有在不起作用的情况下才能使用它们reactive().例如,reactive()只有一个地方定义了变量,所以如果你想在多个地方定义变量,你需要使用reactiveValues().有关reactive()和之间区别的更完整的解释reactiveValues(),您可以从旧帖子中看到我的答案
observe()vs observeEvent():你可以认为它们是同一个东西,但observeEvent()它只是一个observe()由某些变量触发的快捷方式,其余代码是isolate()-ed.事实上,你所做的任何事情observeEvent()也总是可以完成observe(),它是两种相同的东西.