React与观察与观察事件的优势

9rnv2umw  于 2022-12-24  发布在  React
关注(0)|答案(2)|浏览(152)

我已经阅读了所有关于React式编程的资料。我有点困惑。下面的方法都可以,但是什么是首选方法?为什么?显然下面的例子很简单,但是当我用这些方法创建一个更大的应用程序时,我会遇到麻烦吗?
我一直倾向于服务器代码#1中的风格。原因是,我能够分解if语句。对我来说,这似乎更具可读性。同样,下面的简单示例并不非常复杂,但您可以很容易地想象服务器代码2和服务器代码3如何由于大量嵌套的if / if else语句而变得非常混乱。

界面编码

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)

服务器代码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)
xtfmy6hx

xtfmy6hx1#

首先,这些东西有点模棱两可,在某些方面不是很直观,它甚至在闪亮的博客上也是这么说的!
以下是我对这个主题的最佳理解。

    • 让我们从reactive开始**

React函数允许用户监视输入或其他变化变量的状态,并返回值以用于代码中的其他地方。React变量的监视被认为是惰性的,*"React表达式使用惰性求值;也就是说,当它们的依赖关系发生变化时,它们不会立即重新执行,而是等待其他人调用它们。(Source) ". * 您在示例2中很好地展示了这一点,因为您可以在renderText环境中调用变量,一旦调用,React调用中的代码就会执行并重新计算变量。
对于科学书呆子来说,这很像量子力学,通过调用React变量(观察它)导致它通过重新评估而改变,太夸张了吧?

    • 现在到observe**

Observe也是类似的React式,主要的区别是它不返回任何值给除了它自己的环境之外的任何其他环境,而且它不是懒惰的。observe函数持续监控其环境中所有React式值的任何变化,并在这些值发生变化时在其环境中运行代码。因此,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)

值得注意的是,在observe中执行代码的过程中,我们可以操作外部环境的React变量。在您的示例中,您可以分配text <- reactiveValues(),然后通过调用text$result <- 'Hi there'来操作它。我们还可以执行诸如更新selectInput选项或其他闪亮的小部件之类的操作。但是我们不能在这个环境中分配任何非React性变量,就像上面例子中的getStatus一样。这个想法在observe文档中提到过,
观察器类似于React表达式,因为它可以读取React值和调用React表达式,并将在这些依赖项更改时自动重新执行。但与React表达式不同的是,它不会生成结果,也不能用作其他React表达式的输入。因此,观察器仅对它们的副作用有用(例如,执行I/O)(Source

    • 最后,observeEvent**

使用observeEvent的最佳方法是将其视为一个定义的触发器,因为它监视一个事件或变量的变化,然后在事件发生时触发。因为这是一个定义的事件,我希望在按下按钮后发生的事情。它使用了一个isolate环境,我认为这是这个函数如何工作的完美名称。
在这个环境中,我们可以调用一堆React性变量,但是我们只定义了一个作为触发器。observeEventobserve的主要区别在于触发器,因为observe在任何变化的时候都运行,而observeEvent等待触发器。注意,这个环境与观察到的类似,它不返回非React性变量。

    • 摘要**

下面是一个将所有这些观点结合在一起的例子:

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创建一个变量,该变量可以随时间通过用户输入进行更改,仅在调用时计算"lazy"(惰性)。
observe持续监控React性事件和变量,每当ANYReact性变量在环境(观察的环境)中发生变化时,代码就会被评估。可以更改先前定义的React性变量的值,不能创建/返回变量。
observeEvent(多米诺效应)持续监控ONE定义的React性变量/事件(触发器),并在触发器被更改/输入激活时运行代码。可以更改先前定义的React性变量的值,不能创建/返回变量。
eventReactive创建一个变量,该变量具有类似于observeEvent的已定义触发器。如果需要一个根据触发器而不是在调用触发器时求值的React性变量,请使用此选项。
请随时编辑以改进或更正此帖子。

rvpgvaaj

rvpgvaaj2#

已经有了一个非常详细的答案,所以我只需要加上我自己简短的两句话:
尽可能使用reactive()而不是reactiveValues(),普通的reactive()更符合shiny的React式编程哲学,这意味着reactive()表达式只是告诉shiny如何计算变量。而不必指定when。Shiny将负责确定何时计算它。它们将被延迟求值(只有在需要的时候),他们会缓存他们的值,他们会使用书签功能--这正是shiny的设计方式,应该永远是第一选择。
使用reactiveValues(),您现在回到了更加命令式编程的领域,而不是被动的。(或reactiveVal()),但只有在reactive()不起作用时才应使用它们。例如,对于reactive(),只有一个地方定义变量,因此,如果您想在多个位置定义变量,则需要使用reactiveValues()。* 有关reactive()reactiveValues()之间差异的更完整解释,您可以查看我在一篇旧帖子中的回答 *
observe()observeEvent():您可以将它们视为同一件事,但observeEvent()只是observe()的一个快捷方式,由某些变量触发,其余代码是isolate()-ed。实际上,您使用observeEvent()执行的任何操作都可以使用observe()执行,这是同一件事的两种风格。

相关问题