web-dev-qa-db-ja.com

リアクティブ対オブザーブ対オブザーブの利点

ピカピカのリアクティブプログラミングについてできることはすべて読んでいます私は少し混乱しています。以下はすべて機能しますが、推奨される方法は何ですか?その理由は何ですか?以下の例は明らかに単純ですが、いずれかの方法でより大きなアプリケーションを作成するときに問題が発生しますか?

私は、サーバーコード#1のスタイルに引き寄せられる傾向がありました。理由は、ifステートメントを分割できるからです。私には、これはずっと読みやすいようです。繰り返しますが、以下の簡単な例はそれほど複雑ではありませんが、サーバーコード2とサーバーコード3が多数のネストされたif/if elseステートメントと非常に混同しやすいことを簡単に想像できます。

Iコード

library(shiny)

ui <- fluidPage(
  selectInput(inputId = 'choice',
              label = 'Choice',
              choice = c('Hello','Goodbye'),
              selected = c('Hello')
  ),

  textOutput('result')

)

サーバーコード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)

サーバーコード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)

サーバーコード

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)
26
agf1997

まず第一に、このようなことは曖昧であり、ある意味ではあまり直感的ではありません。Shinyブログでもそう言っています。

これが私のトピックに関する私の最高の理解です。

reactiveで始まります

リアクティブ関数を使用すると、ユーザーは入力またはその他の変化する変数の状態を監視し、コードの他の場所で使用される値を返すことができます。リアクティブ変数の監視はレイジーと見なされます」リアクティブ式はレイジー評価を使用します。つまり、依存関係が変更されるとすぐに再実行されず、誰かによって呼び出されるまで待機しますelse。( Source) "。リアクティブコール内のコードが呼び出されるとrenderText環境内で変数を呼び出すことができるため、これを例2でよく示しています。変数を評価します。

科学オタクにとって、これは量子力学に非常によく似ています。リアクティブ変数を呼び出す(それを観察する)ことで、再評価によって変化します。

observe

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)

enter image description here

注目すべき重要なことは、observeで実行されるコード中に、外部の環境反応変数を操作できることです。あなたの場合、text <- reactiveValues()を割り当て、text$result <- 'Hi there'を呼び出してそれを操作します。 selectInput選択肢の更新やその他の光沢のあるウィジェットのようなこともできますが、上記の例のgetStatusのようなこの環境では非反応変数を割り当てることはできません。そして、この考えはobserveのドキュメントで言及されています。

「オブザーバーは、リアクティブな値を読み取り、リアクティブな式を呼び出すことができるという点でリアクティブな式に似ています。これらの依存関係が変化すると、自動的に再実行されます。しかし、リアクティブな式とは異なり、結果を生成せず、他のリアクティブ式への入力。したがって、オブザーバーは副作用(たとえば、I/Oの実行)のみに役立ちます( Source ) "

最後に、observeEvent

observeEventを使用する最良の方法は、1つのイベントまたは変数の変更を監視し、イベントが発生したときに起動するように、定義されたトリガーと考えることです。これは、ボタンへの入力を監視するために最もよく使用します。これは、ボタンが押された後に発生するように定義されたイベントであるためです。 isolate環境を使用します。これは、この関数がどのように機能するかを示す完璧な名前だと思います。

この環境内では、一連のリアクティブ変数を呼び出すことができますが、トリガーとして定義するのは1つだけです。 observeEventがトリガーになり、observeが主に異なります。これは、observeが変更されるたびに実行され、observeEventがトリガーを待機するためです。この環境は、非反応変数を返さないという点でobserveに似ていることに注意してください。

概要

これらすべてのアイデアをまとめた例を次に示します。

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)

reactiveユーザー入力によって時間とともに変更できる変数を作成し、呼び出された場合にのみ「遅延」の意味を評価します。

observe反応性のイベントと変数を継続的に監視し、ANY反応性変数が環境(観測された環境)で変更されるたびに、コードが評価されます。以前に定義されたリアクティブ変数の値を変更できますが、変数を作成/返すことはできません。

observeEvent(Domino Effect)継続的にモニターONE定義されたリアクティブ変数/イベント(トリガー)とトリガーが変更によってアクティブになったときにコードを実行/そのトリガーの入力。以前に定義されたリアクティブ変数の値を変更できますが、変数を作成/返すことはできません。

eventReactiveobserveEventと同様の定義済みトリガーを使用して、変数を作成します。これは、トリガーされたときに評価されるリアクティブ変数が必要な場合に使用します。

これがお役に立てば幸いです。理解に誤りがある場合、またはより明確な説明がある場合は、この回答を自由に編集してください。

26
Chabo

すでに非常に詳細な答えがありますので、私は自分の短い単純な2セントを追加します。

可能な限り、reactive()ではなくreactiveValues()に固執します。通常のreactive()は、シャイニーリアクティブプログラミング哲学とよりインラインで動作します。つまり、reactive()式は、シャイニーhowwhenを指定せずに変数が計算されます。 Shinyは、いつ計算するかを決定します。それらは遅延評価され(必要な場合のみ)、値をキャッシュし、ブックマーク機能を使用します。これは光沢のあるデザインの方法であり、常に最初に選択する必要があります。

reactiveValues()を使用すると、リアクティブではなく、より多くの命令プログラミング領域に戻ります。 reactive()がカットしない場合があり、reactiveValues()(またはreactiveVal())を使用する必要がありますが、reactive()が機能しない場合にのみ使用してください。たとえば、reactive()の場合、変数が定義される場所は1つだけなので、複数の場所で変数を定義する場合は、reactiveValues()を使用する必要があります。 reactive()reactiveValues()の違いに関するより完全な説明については、 古い投稿からの私の回答を参照してください。

observe() vs observeEvent():これらは同じものと考えることができますが、observeEvent()は、特定の変数によってトリガーされるobserve()のショートカットであり、コードはisolate()- edです。実際、observeEvent()で行うことは常にobserve()でも行うことができ、同じことの2つのフレーバーです。

8
DeanAttali