mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-10 23:48:01 -05:00
Compare commits
1 Commits
rm-babel
...
getCurrent
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89026ee1ae |
@@ -84,6 +84,7 @@ export(fluidPage)
|
||||
export(fluidRow)
|
||||
export(formatStackTrace)
|
||||
export(freezeReactiveValue)
|
||||
export(getCurrentObserver)
|
||||
export(getDefaultReactiveDomain)
|
||||
export(getShinyOption)
|
||||
export(h1)
|
||||
|
||||
125
R/reactives.R
125
R/reactives.R
@@ -703,6 +703,10 @@ execCount <- function(x) {
|
||||
|
||||
# Observer ------------------------------------------------------------------
|
||||
|
||||
# The initial value of "current observer" is NULL (and will always be NULL,
|
||||
# except when within the scope of the observe or observeEvent)
|
||||
.globals$currentObserver <- NULL
|
||||
|
||||
Observer <- R6Class(
|
||||
'Observer',
|
||||
portable = FALSE,
|
||||
@@ -814,6 +818,8 @@ registerDebugHook("observerFunc", environment(), label)
|
||||
run = function() {
|
||||
ctx <- .createContext()
|
||||
.execCount <<- .execCount + 1L
|
||||
.globals$currentObserver <- self
|
||||
on.exit(.globals$currentObserver <- NULL) # On exit, set it back to NULL
|
||||
ctx$run(.func)
|
||||
},
|
||||
onInvalidate = function(callback) {
|
||||
@@ -904,6 +910,125 @@ registerDebugHook("observerFunc", environment(), label)
|
||||
)
|
||||
)
|
||||
|
||||
#' Return the current observer
|
||||
#'
|
||||
#' This function is useful when you want to access an observer's methods or
|
||||
#' variables directly. For example, you may have logic that destroys or
|
||||
#' suspends the observer (from within its own scope) on some condition.
|
||||
#'
|
||||
#' This function works by returning the observer that is currently being run
|
||||
#' when \code{getCurrentObserver()} is called. If there is no observer being
|
||||
#' run (for example, if you called it from outside of a reactive context),
|
||||
#' it will always return \code{NULL}. There are a few subtleties, however.
|
||||
#' Consider the following five situations:
|
||||
#'
|
||||
#' \enumerate{
|
||||
#' \item \code{getCurrentObserver() #outside of a reactive context}
|
||||
#' \item \code{observe({ getCurrentObserver() }) }
|
||||
#' \item \code{observe({ (function(){ getCurrentObserver() })() )} }
|
||||
#' \item \code{observe({ isolate({ getCurrentObserver() }) }) }
|
||||
#' \item \code{observe({ reactive({ getCurrentObserver() }) }) }
|
||||
#' }
|
||||
#'
|
||||
#' In (1), since you're outside of a reactive context, we've already
|
||||
#' established that \code{getCurrentObserver()} will return \code{NULL}.
|
||||
#' In (2), we have the "vanilla" case, in which \code{getCurrentObserver()}
|
||||
#' is called directly from within the body of the \code{observe} call.
|
||||
#' This returns that observer. So far, so good. The problem comes with
|
||||
#' the last three cases -- should we be able to "retrieve" the outer
|
||||
#' observer if we're inside an inner function's scope, or inside of an
|
||||
#' \code{isolate} or a \code{reactive} block?
|
||||
#'
|
||||
#' Before we can even asnwer that, there is an important distinction to
|
||||
#' be made here: are function calls, \code{reactive} calls and
|
||||
#' \code{isolate} blocks the same \emph{type} of thing? As far as Shiny
|
||||
#' is concerned, the answer is no. Shiny-specific things (like observers,
|
||||
#' reactives and code inside of an \code{isolate} chunk) exist in what we
|
||||
#' call reactive contexts. Each run of an observer or a reactive is
|
||||
#' associated with a particular reactive context. But regular functions
|
||||
#' have no relation to reactive contexts. So, while calling a regular
|
||||
#' function inside of an observer does not change the reactive context,
|
||||
#' calling a \code{reactive} or \code{isolate} certainly does.
|
||||
#'
|
||||
#' With this distinction in mind, we can refine our definition of
|
||||
#' \code{getCurrentObserver()} as follows: it returns the observer (if any)
|
||||
#' that is currently running, as long as it is called from within the
|
||||
#' same reactive context that was created when the observer started
|
||||
#' running. If the reactive context changed (most likely because of a
|
||||
#' call to \code{reactive} or \code{isolate}), \code{getCurrentObserver}
|
||||
#' will return \code{NULL}. (There is another common way that the reactive
|
||||
#' context can change inside an observer, which is if there is a second,
|
||||
#' nested observer. In this case, \code{getCurrentObserver()} will return
|
||||
#' the second, nested observer, since that is the one that is actually
|
||||
#' running at that time.)
|
||||
#'
|
||||
#' So to recap, here's the return value for each of the five situations:
|
||||
#' \enumerate{
|
||||
#' \item \code{NULL}
|
||||
#' \item the observer
|
||||
#' \item the observer
|
||||
#' \item \code{NULL}
|
||||
#' \item \code{NULL}
|
||||
#' }
|
||||
#'
|
||||
#' Now, you may be wondering why \code{getCurrentObserver()} should't be able
|
||||
#' to get the running observer even if the reactive context changes. This isn't
|
||||
#' technically impossible. In fact, if you want this behavior for some reason,
|
||||
#' you can set the argument \code{dig} to be \code{TRUE}, so that the function
|
||||
#' will "dig" through the reactive contexts until it retrieves the one for the
|
||||
#' observer and returns the observer.
|
||||
#'
|
||||
#' So, with \code{dig = TRUE}, here's the return value for each of the five
|
||||
#' situations:
|
||||
#' \enumerate{
|
||||
#' \item \code{NULL}
|
||||
#' \item the observer
|
||||
#' \item the observer
|
||||
#' \item the observer
|
||||
#' \item the observer
|
||||
#' }
|
||||
#'
|
||||
#' The reason that this is not the default (or even encouraged) is because
|
||||
#' things can get messy quickly when you cross reactive contexts at will.
|
||||
#' For example, the return value of a \code{reactive} call is cached and that
|
||||
#' reactive is not re-run unless its reactive dependencies change. If that
|
||||
#' reactive has a call to \code{getCurrentObserver()}, this can produce
|
||||
#' undesirable and unintuitive results.
|
||||
#'
|
||||
#' @param dig If \code{FALSE} (default), \code{getCurrentObserver} will only
|
||||
#' return the observer if it's invoked directly from within the observer's
|
||||
#' body or from a regular function. If \code{TRUE}, it will always return
|
||||
#' the observer (if it exists on the stack), even if it's invoked from
|
||||
#' within a \code{reactive} or an \code{isolate} scope. See below for more
|
||||
#' information.
|
||||
#'
|
||||
#' @return The observer (created with a call to either \code{observe} or to
|
||||
#' \code{observeEvent}) that is currently running.
|
||||
#'
|
||||
#' @seealso \code{\link{observe}}
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
#' shinyApp(
|
||||
#' ui = basicPage( actionButton("go", "Go")),
|
||||
#' server = function(input, output, session) {
|
||||
#' observeEvent(input$go, {
|
||||
#' print(paste("This will only be printed once; all",
|
||||
#' "subsequent button clicks won't do anything"))
|
||||
#' getCurrentObserver()$destroy()
|
||||
#' })
|
||||
#' }
|
||||
#' )
|
||||
#' }
|
||||
#' @export
|
||||
getCurrentObserver <- function(dig = FALSE) {
|
||||
o <- .globals$currentObserver
|
||||
ctx <- getCurrentContext()
|
||||
if (!dig && !is.null(o) && ctx$id != o$.ctx$id) o <- NULL
|
||||
o
|
||||
}
|
||||
|
||||
#' Create a reactive observer
|
||||
#'
|
||||
#' Creates an observer from the given expression.
|
||||
|
||||
@@ -124,6 +124,7 @@ sd_section("Reactive constructs",
|
||||
"makeReactiveBinding",
|
||||
"observe",
|
||||
"observeEvent",
|
||||
"getCurrentObserver",
|
||||
"reactive",
|
||||
"reactiveFileReader",
|
||||
"reactivePoll",
|
||||
|
||||
124
man/getCurrentObserver.Rd
Normal file
124
man/getCurrentObserver.Rd
Normal file
@@ -0,0 +1,124 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/reactives.R
|
||||
\name{getCurrentObserver}
|
||||
\alias{getCurrentObserver}
|
||||
\title{Return the current observer}
|
||||
\usage{
|
||||
getCurrentObserver(dig = FALSE)
|
||||
}
|
||||
\arguments{
|
||||
\item{dig}{If \code{FALSE} (default), \code{getCurrentObserver} will only
|
||||
return the observer if it's invoked directly from within the observer's
|
||||
body or from a regular function. If \code{TRUE}, it will always return
|
||||
the observer (if it exists on the stack), even if it's invoked from
|
||||
within a \code{reactive} or an \code{isolate} scope. See below for more
|
||||
information.}
|
||||
}
|
||||
\value{
|
||||
The observer (created with a call to either \code{observe} or to
|
||||
\code{observeEvent}) that is currently running.
|
||||
}
|
||||
\description{
|
||||
This function is useful when you want to access an observer's methods or
|
||||
variables directly. For example, you may have logic that destroys or
|
||||
suspends the observer (from within its own scope) on some condition.
|
||||
}
|
||||
\details{
|
||||
This function works by returning the observer that is currently being run
|
||||
when \code{getCurrentObserver()} is called. If there is no observer being
|
||||
run (for example, if you called it from outside of a reactive context),
|
||||
it will always return \code{NULL}. There are a few subtleties, however.
|
||||
Consider the following five situations:
|
||||
|
||||
\enumerate{
|
||||
\item \code{getCurrentObserver() #outside of a reactive context}
|
||||
\item \code{observe({ getCurrentObserver() }) }
|
||||
\item \code{observe({ (function(){ getCurrentObserver() })() )} }
|
||||
\item \code{observe({ isolate({ getCurrentObserver() }) }) }
|
||||
\item \code{observe({ reactive({ getCurrentObserver() }) }) }
|
||||
}
|
||||
|
||||
In (1), since you're outside of a reactive context, we've already
|
||||
established that \code{getCurrentObserver()} will return \code{NULL}.
|
||||
In (2), we have the "vanilla" case, in which \code{getCurrentObserver()}
|
||||
is called directly from within the body of the \code{observe} call.
|
||||
This returns that observer. So far, so good. The problem comes with
|
||||
the last three cases -- should we be able to "retrieve" the outer
|
||||
observer if we're inside an inner function's scope, or inside of an
|
||||
\code{isolate} or a \code{reactive} block?
|
||||
|
||||
Before we can even asnwer that, there is an important distinction to
|
||||
be made here: are function calls, \code{reactive} calls and
|
||||
\code{isolate} blocks the same \emph{type} of thing? As far as Shiny
|
||||
is concerned, the answer is no. Shiny-specific things (like observers,
|
||||
reactives and code inside of an \code{isolate} chunk) exist in what we
|
||||
call reactive contexts. Each run of an observer or a reactive is
|
||||
associated with a particular reactive context. But regular functions
|
||||
have no relation to reactive contexts. So, while calling a regular
|
||||
function inside of an observer does not change the reactive context,
|
||||
calling a \code{reactive} or \code{isolate} certainly does.
|
||||
|
||||
With this distinction in mind, we can refine our definition of
|
||||
\code{getCurrentObserver()} as follows: it returns the observer (if any)
|
||||
that is currently running, as long as it is called from within the
|
||||
same reactive context that was created when the observer started
|
||||
running. If the reactive context changed (most likely because of a
|
||||
call to \code{reactive} or \code{isolate}), \code{getCurrentObserver}
|
||||
will return \code{NULL}. (There is another common way that the reactive
|
||||
context can change inside an observer, which is if there is a second,
|
||||
nested observer. In this case, \code{getCurrentObserver()} will return
|
||||
the second, nested observer, since that is the one that is actually
|
||||
running at that time.)
|
||||
|
||||
So to recap, here's the return value for each of the five situations:
|
||||
\enumerate{
|
||||
\item \code{NULL}
|
||||
\item the observer
|
||||
\item the observer
|
||||
\item \code{NULL}
|
||||
\item \code{NULL}
|
||||
}
|
||||
|
||||
Now, you may be wondering why \code{getCurrentObserver()} should't be able
|
||||
to get the running observer even if the reactive context changes. This isn't
|
||||
technically impossible. In fact, if you want this behavior for some reason,
|
||||
you can set the argument \code{dig} to be \code{TRUE}, so that the function
|
||||
will "dig" through the reactive contexts until it retrieves the one for the
|
||||
observer and returns the observer.
|
||||
|
||||
So, with \code{dig = TRUE}, here's the return value for each of the five
|
||||
situations:
|
||||
\enumerate{
|
||||
\item \code{NULL}
|
||||
\item the observer
|
||||
\item the observer
|
||||
\item the observer
|
||||
\item the observer
|
||||
}
|
||||
|
||||
The reason that this is not the default (or even encouraged) is because
|
||||
things can get messy quickly when you cross reactive contexts at will.
|
||||
For example, the return value of a \code{reactive} call is cached and that
|
||||
reactive is not re-run unless its reactive dependencies change. If that
|
||||
reactive has a call to \code{getCurrentObserver()}, this can produce
|
||||
undesirable and unintuitive results.
|
||||
}
|
||||
\examples{
|
||||
## Only run examples in interactive R sessions
|
||||
if (interactive()) {
|
||||
shinyApp(
|
||||
ui = basicPage( actionButton("go", "Go")),
|
||||
server = function(input, output, session) {
|
||||
observeEvent(input$go, {
|
||||
print(paste("This will only be printed once; all",
|
||||
"subsequent button clicks won't do anything"))
|
||||
getCurrentObserver()$destroy()
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{observe}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user