In Shiny tutorial, there is an example:
fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2)) shinyServer(function(input, output) { currentFib <- reactive({ fib(as.numeric(input$n)) }) output$nthValue <- renderText({ currentFib() }) output$nthValueInv <- renderText({ 1 / currentFib() }) })
I don't get how reactive
caches the values. Does it internally do something like return(function() cachedValue)
? Now I am wondering if I can do this?
fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2)) shinyServer(function(input, output) { currentFib <- reactiveValues({ fib(as.numeric(input$n)) }) output$nthValue <- renderText({ currentFib }) output$nthValueInv <- renderText({ 1 / currentFib }) })
Reactive values are an implementation of Reactive sources; that is, they are an implementation of that role. Reactive expressions are an implementation of Reactive conductors. They can access reactive values or other reactive expressions, and they return a value. Observers are an implementation of Reactive endpoints.
A reactive expression is an R expression that uses widget input and returns a value. The reactive expression will update this value whenever the original widget changes. To create a reactive expression use the reactive function, which takes an R expression surrounded by braces (just like the render* functions).
In the simplest of terms reactivity/reactive programming is the ability of a program to compute outputs from a given set of user inputs. The ability of a shiny app to handle reactivity makes a two-way communication between the user and the existing information.
Reactive functions are functions that can read reactive values and call other reactive functions. Whenever a reactive value changes, any reactive functions that depended on it are marked as "invalidated" and will automatically re-execute if necessary.
Using currentFib <- reactiveValues({ fib(as.numeric(input$n)) })
will not work in this context. You will get an error saying that you are accessing reactive values outside of the "reactive context."
However, if you wrap it inside a function call instead, it will work:
currentFib <- function(){ fib(as.numeric(input$n)) }
This works because now the function call is inside a reactive context.
The key difference is the distinction they make in the Shiny documentation, between reactive "sources" and "conductors." In that terminology, reactive({...})
is a conductor, but reactiveValues
can only be a source.
Here's how I think of reactiveValues
- as a way to extend input
which gets specified in UI.R. Sometimes, the slots in input
are not enough, and we want derived values based on those input slots. In other words, it is a way to extend the list of input
slots for future reactive computations.
Reactive()
does what you say -- it returns the value, after re-running the expression each time any reactive Value changes. If you look at the source code for reactive
you can see it: The last line is that cached value that is being returned: Observable$new(fun, label)$getValue
where 'fun' is the expression that was sent in the call to reactive.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With