Как блестяще определить зависимости - PullRequest
1 голос
/ 08 ноября 2019

Работая над приложением, я заметил, что блестящий пересчитывает вывод, когда он не нужен (на мой взгляд), и, похоже, он зависит от вложенности в reactiveValues.

UI:

library(shiny)
n <- 5
o <- paste0('o', 1:n)
ui <- fluidPage(
  lapply(o, function(x) textOutput(x)),
  actionButton('a1', 'a1')
)

Сервер один (пересчитывает выходные данные, как я ожидал):

server <- function(input, output){
  rv <- reactiveValues(o1='a', o2='b', o3='c', o4='d', o5='e')
  lapply(o, function(x){
    output[[x]] <- renderText({
      cat('rendering', x, '\n')
      rv[[x]]
    })
  })
  observeEvent(input$a1, {
    rv$o1 <- rnorm(1)
  })
}

Сервер два (каждый выход пересчитывается при нажатии кнопки):

server <- function(input, output){
  rv <- reactiveValues(
    # difference with server one is that o1-5 are nested in l
    l=list(o1='a', o2='b', o3='c', o4='d', o5='e')
  )
  lapply(o, function(x){
    output[[x]] <- renderText({
      cat('rendering', x, '\n')
      rv$l[[x]]
    })
  })
  observeEvent(input$a1, {
    rv$l$o1 <- rnorm(1)
  })
}

При запускеприложение с сервером одно, каждый раз, когда нажимается кнопка, только o1 пересчитывается (как напечатано в консоли). Однако при запуске приложения с сервером два, каждый раз, когда нажимается кнопка, все результаты пересчитываются.

Мне было интересно, как блестяще определяются зависимости. Может ли он различать зависимости только на верхнем уровне reactiveValues или есть способ заставить вывод зависеть только от более глубокого уровня reactiveValues? Другими словами, если мне нужна / нужна ситуация, как на втором сервере, могу ли я предотвратить пересчет выходов, отличных от o1, при нажатии кнопки?

1 Ответ

1 голос
/ 12 ноября 2019

При shiny reactiveValues каждый отдельный объект в целом является реактивным компонентом: если что-то находится в его структуре (vector, list, data.frame,и т. д.) изменяется, то считается, что объект в целом изменился (и, следовательно, что-то на него отреагирует).

Чтобы обсудить, можно ли реагировать на подкомпоненты, вот что: любой объект будетсчитаться рекурсивным . Первый пример реакции на компоненты верхнего уровня list, это не так уж плохо ... но если отслеживаемая вещь имеет много уровней (и нет причин или мер предосторожности, препятствующих этому), то каждыйвремя что-то случается, если бы shiny глубоко изучить каждый отдельный компонент объекта, было бы много накладных расходов. Масштабирование будет плохим.

В целях организации поймите, что вы можете иметь несколько независимых reactiveValues компонентов. Хотя я сомневаюсь, что это сильно повлияет на производительность, можно сделать следующее:

server <- function(input, output){
  rv1 <- reactiveValues(o1='a', o2='b', o3='c')
  rv2 <- reactiveValues(o4='d', o5='e')
  # ...
}

И, честно говоря, в некоторых случаях это может быть лучше: насколько компактность (один супер-огромный вызов reactiveValues)может быть немного быстрее (хотя я все еще не знаю, что это правда), можно утверждать, что читаемость напрямую влияет на удобство обслуживания и устранение неполадок ,Если реактивные значения имеют декларативную группировку, это может иметь большое значение, если вы (или кто-то еще) посмотрите на свой код после нескольких месяцев бездействия.

...