この質問は this one に関連しています。 2つは同じ機能を生成できますが、実装はわずかに異なります。 1つの重要な違いは、reactiveValue
は_input$
_のような複数の値を持つことができるコンテナーであるということです。 shiny documentation では、通常、機能はreactive()
を使用して実装されますが、ほとんどの場合、reactiveValues()
がより便利です。ここで何かキャッチはありますか?私が気づいていないかもしれない2つの間に他の大きな違いはありますか?これら2つのコードスニペットは同等ですか?
以下を使用して実装された同じ コード例 を参照してください。
反応式:
_library(shiny)
ui <- fluidPage(
shiny::numericInput(inputId = 'n',label = 'n',value = 2),
shiny::textOutput('nthValue'),
shiny::textOutput('nthValueInv')
)
fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2))
server<-shinyServer(function(input, output, session) {
currentFib <- reactive({ fib(as.numeric(input$n)) })
output$nthValue <- renderText({ currentFib() })
output$nthValueInv <- renderText({ 1 / currentFib() })
})
shinyApp(ui = ui, server = server)
_
無効値:
_library(shiny)
ui <- fluidPage(
shiny::numericInput(inputId = 'n',label = 'n',value = 2),
shiny::textOutput('nthValue'),
shiny::textOutput('nthValueInv')
)
fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2))
server<-shinyServer(function(input, output, session) {
myReactives <- reactiveValues()
observe( myReactives$currentFib <- fib(as.numeric(input$n)) )
output$nthValue <- renderText({ myReactives$currentFib })
output$nthValueInv <- renderText({ 1 / myReactives$currentFib })
})
shinyApp(ui = ui, server = server)
_
あなたの例では役に立たないでしょうが、キャッチがあります。
shiny開発者はreactive()
をlazyに設計しました、その中に含まれる式は、その依存関係の1つによって呼び出されたときにのみ実行されることを意味します。リアクティブな依存関係の1つが変更されると、キャッシュをクリアし、自身の依存関係に通知しますが、それらの依存関係の1つから要求されるまで、それ自体は実行されません。 (つまり、その唯一の依存要素が非表示タブのtextOutput()
要素である場合、そのタブが開かれない限り、実際には実行されません。)
一方、observe()
はeager;です。含まれる式は、その依存関係のいずれかが変更されるたびにすぐに実行されます-その値がその依存関係のいずれかによって必要でなくても(そして実際にはhas依存関係がなくても)。そのような熱意は、副作用のためにobserve()
を呼び出している場合はdesirableですが、渡すためだけに使用している場合はwasteful他のリアクティブ式または行のエンドポイントへのコンテンツの戻り値。
Joe Chengは、2016年の「効果的なリアクティブプログラミング」に関するShiny Developer Conferenceプレゼンテーション でこの区別を非常によく説明しています 。特に、プレゼンテーションの2時間目の30時20分頃から始まるビットを参照してください。あなたが40:42まで見たら(点滅して見逃すでしょう!)彼はあなたが好きなobserve()
/reactiveValue ()
の組み合わせの動作を簡単に特徴づけます。
2つの構成要素が類似していること、そして問題を解決するためにどちらか一方を何度も使用できることは事実です。しかし通常、どちらかを使用する方が理にかなっています。
フィボナッチの場合、reactive()
式を使用する方が理にかなっていると思います。なぜなら、currentFib
は非常に特定の予測可能な時間に変更する必要があるためです(つまり、input$n
が変更されると、それに応じて更新、またはreactその変更に対して)。
しかし、他のいくつかのケースでは、reactiveValues
を使用する方が簡単で良いかもしれません。 2つの例を示します。
最初に、何らかの値が更新されることに反応するのではなく)何らかの状態を持つと考える変数があるときはいつでも、reactiveValues
を使用する方が良いと思います。
例:
library(shiny)
ui <- fluidPage(
"Total:",
textOutput("total", inline = TRUE),
actionButton("add1", "Add 1"),
actionButton("add5", "Add 5")
)
server <- function(input, output, session) {
values <- reactiveValues(total = 0)
observeEvent(input$add1, {
values$total <- values$total + 1
})
observeEvent(input$add5, {
values$total <- values$total + 5
})
output$total <- renderText({
values$total
})
}
shinyApp(ui = ui, server = server)
上記のコードには、可変状態を持つtotal
変数があり、それを典型的な変数と考えてそのように使用する方がはるかに直感的です。これは、reactiveValues
を使用する場合の最も一般的なケースです。
また、変数を複数の場所で更新できる場合はreactiveValues
を使用します。フィボナッチの例から借用するには、次の光沢のあるアプリを検討します。ここで、n
番号は2つの入力のいずれかで設定できます:
library(shiny)
fib <- function(n) ifelse(n < 3, 1, fib(n - 1) + fib(n - 2))
ui <- fluidPage(
selectInput("nselect", "Choose a pre-defined number", 1:10),
numericInput("nfree", "Or type any number", 1),
"Fib number:",
textOutput("nthval", inline = TRUE)
)
server <- function(input, output, session) {
values <- reactiveValues(n = 1)
observeEvent(input$nselect, {
values$n <- input$nselect
})
observeEvent(input$nfree, {
values$n <- input$nfree
})
output$nthval <- renderText({
fib(as.integer(values$n))
})
}
shinyApp(ui = ui, server = server)
この例はフィボナッチのコンテキストでは少し奇妙に思えるかもしれませんが、他の複雑なアプリでどのように表示されるかを期待できます。変数の値をさまざまな場所に設定したい場合があります。 1つのブロックに実装する必要があるリアクティブ式ではなく、reactiveValue。
うまくいけば、これが役に立ち、理にかなっています。もちろん、これはこのテーマに対する私の個人的な見解にすぎません。それは必ずしも光沢のある開発者が意図したものではありませんが、これが2つの方法の使用方法を学んだ方法です。