官方文档
https://shiny.rstudio.com/articles/understanding-reactivity.html
理解
1. reactive 和 eventReactive
reactive 是模块化反应机制,如下代码中fib(as.numeric(input$n))
被单独执行了两次,浪费资源。
fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2))
server <- function(input, output) {
output$nthValue <- renderText({ fib(as.numeric(input$n)) })
output$nthValueInv <- renderText({ 1 / fib(as.numeric(input$n)) })
}
我们使用reactive可以生成一个中间表达式,暂存结果在currentFib
,后面调用currentFib
省去计算过程。
fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2))
server <- function(input, output) {
currentFib <- reactive({ fib(as.numeric(input$n)) })
output$nthValue <- renderText({ currentFib() })
output$nthValueInv <- renderText({ 1 / currentFib() })
}
reactive会时刻监视 input 的每一个改变做出响应,但是有时候我们并不希望如此。例如运用多个条件对数据进行筛选的时候,我们可能是一个一个条件输入的,并不希望每改变一个条件就输出一个表格或者图片,这样会很浪费计算资源。这个时候希望更改完所有条件后,一起提交输入,进行计算,需要用到eventReactive。
## 这个例子在拖动控件的时候,输出的表格会随着变化
library("shiny")
shinyApp(
ui = fluidPage(
column(4,
sliderInput("x", "Value",
min = 1, max = 10,
value = 3),
actionButton("button", "Show")
),
column(8, tableOutput("table"))
),
server = function(input, output) {
df <-reactive({
head(cars, input$x)
})
output$table <- renderTable({
df()
})
}
)
## 这个滑动控件后,只有监视到按钮事件,输出才发生改变
shinyApp(
ui = fluidPage(
column(4,
sliderInput("x", "Value",
min = 1, max = 10,
value = 3),
br(),
actionButton("button", "Show")
),
column(8, tableOutput("table"))
),
server = function(input, output) {
df <- eventReactive(input$button, {
head(cars, input$x)
})
output$table <- renderTable({
df()
})
}
)
2. observe 和 observeEvent
observe 和 reactive 相同点都是能响应 input 的变化,不同点是 observer 没有返回值,不能向下传递,所以就不能作为 render 的输入。顾名思义,它只是起监视作用。下面例子,当滑动使 x > 5时,界面发送通知。
shinyApp(
ui = fluidPage(
sliderInput("x", "Value",
min = 1, max = 10,
value = 3)
),
server = function(input, output) {
observe({
if(input$x > 5)
showNotification("value > 5")
})
}
)
相同的 observeEvent 只是再增加一个监视条件,起延时作用。例如下面例子,滑动滑杆时,并不去判断 x > 5,只有按下按钮,才执行下面的代码。
shinyApp(
ui = fluidPage(
sliderInput("x", "Value",
min = 1, max = 10,
value = 3),
actionButton("go", "Go")
),
server = function(input, output) {
observeEvent(input$go,{
if(input$x > 5)
showNotification("value > 5")
})
}
)