observer concept in the reactive programming shiny app

Viewed 22

I wonder if anybody can explain the following concepts about the observer (taken from here) in the simplest way possible.? Why is every time that x changes the number of times is printed increases?

enter image description here

x <- reactiveVal(1)
y <- observe({
  x()
  observe(print(x()))
})

#> [1] 1
x(2)
#> [1] 2
#> [1] 2
x(3)
#> [1] 3
#> [1] 3
#> [1] 3
2 Answers

As I said, it's not easy for me to explain better than the last given sentence. Each time x() changes, a new nested observer is created. The first one performs print(x), the second one as well, etc. Each one prints the value of x.

The code below shows that there are three nested observers at the end, but there's another difficulty, namely understanding local().

library(shiny)
reactiveConsole(TRUE)

x <- reactiveVal(1)
i <- 0
observe({
  x()
  i <<- i + 1
  local({
    j <- i
    observe({
      x()
      print(paste("Hello I am the nested observer", j))
    })
  })
})
# [1] "Hello I am the nested observer 1"
# > x(12)
# [1] "Hello I am the nested observer 1"
# [1] "Hello I am the nested observer 2"
# > x(16)
# [1] "Hello I am the nested observer 1"
# [1] "Hello I am the nested observer 2"
# [1] "Hello I am the nested observer 3"

Think about this one too:

x <- reactiveVal(1)
observe({
  x()
  local({
    y <- x()
    observe({
      x()
      print(y)
    })
  })
})
# [1] 1
# > x(5)
# [1] 1
# [1] 5
# > x(9)
# [1] 1
# [1] 5
# [1] 9

This other example is instructive as well:

x <- reactiveVal(10)
observe({
  x()
  observe({
    req(x() >= 3)
    print(x())
  })
})
# [1] 10
# > x(2) # a new nested observer is created but it doesn't react because 2 < 3
# > x(1) # a new nested observer is created but it doesn't react because 1 < 3
# > x(4) # a new nested observer is created and it reacts because 4 >= 3
# [1] 4
# [1] 4
# [1] 4
# [1] 4

I don't like the example since it is immediately followed by:

As a general rule, you should only ever create observers or outputs at the top-level of your server function. If you find yourself trying to nest them or create an observer inside an output, sit down and sketch out the reactive graph that you’re trying to create — there’s almost certainly a better approach.

That said, the point is that the observer is created regardless of if or what it is assigned to. Each time x changes, the statement inside of y runs again. That statement creates a NEW unique observer that prints x. It does not overwrite the previously created observer. By changing x 3 times, you've created 3 unique printing observers.

Related