Compare commits

...

18 Commits

Author SHA1 Message Date
Barret Schloerke
550b679e61 Add news item 2020-03-16 10:29:15 -04:00
Barret Schloerke
8ada448c51 add test to make sure the reactive and reactiveVal objects are functions 2020-03-12 17:55:42 -04:00
Barret Schloerke
106ad74d2b add the class 'function' to a reactiveVal object 2020-03-12 17:55:23 -04:00
Barret Schloerke
0a6260259a add the class 'function' to a reactive object 2020-03-12 17:48:41 -04:00
Barret Schloerke
78f9132eb3 Fix Travis checks (#2791)
* make sure the server is only run if the example is interactive

* get travis to pass for now

* Update modules.R

* Add S3 class to MockShinySession

* un-skip test

* Update roxygen level

Co-authored-by: Alan Dipert <alan@dipert.org>
2020-03-12 17:42:38 -04:00
Winston Chang
15476ac32e Merge pull request #2789 from rstudio/skip-tests-timing
Skip debounce/throttle tests on CRAN
2020-03-12 11:16:20 -05:00
Winston Chang
17fb5b9eae Add link 2020-03-12 10:00:36 -05:00
Winston Chang
fd27a0dfa2 Skip debounce/throttle tests on CRAN 2020-03-12 09:46:18 -05:00
Winston Chang
5ffe69ec6c Merge tag 'v1.4.0.1' 2020-03-12 09:21:07 -05:00
Carson
f5723b2a4d revert man/ changes to reflect CRAN version of htmltools 2020-03-11 12:04:58 -05:00
Carson
212b33a0ce bump version 2020-03-03 18:50:41 -06:00
Carson
6b7a121161 yarn build 2020-03-03 18:50:34 -06:00
Carson Sievert
c89da718b1 Merge pull request #2777 from rstudio/fix-docs
Run tools/updateHtmltools.R
2020-03-03 18:40:27 -06:00
Carson
eef3ae8387 update news and update htmltools docs 2020-03-03 16:45:57 -06:00
Winston Chang
0c53d54347 Merge pull request #2776 from rstudio/grid-r-devel
Patches for grid 4.0
2020-03-03 16:12:39 -06:00
Carson
cbbb04cf69 yarn build 2020-03-03 15:52:25 -06:00
Carson
120baf0a6e review feedback 2020-03-03 15:34:32 -06:00
Carson
685dc7cc3a Updates for new grid in r-devel 2020-03-03 15:30:12 -06:00
12 changed files with 98 additions and 14 deletions

View File

@@ -173,6 +173,6 @@ Collate:
'test-module.R'
'test.R'
'update-input.R'
RoxygenNote: 7.0.2
RoxygenNote: 7.1.0
Encoding: UTF-8
Roxygen: list(markdown = TRUE)

View File

@@ -19,6 +19,8 @@ shiny 1.4.0.9001
* `getDefaultReactiveDomain()` can now be called inside a `session$onSessionEnded` callback and will return the calling `session` information. ([#2757](https://github.com/rstudio/shiny/pull/2757))
* Added a `'function'` class to `reactive()` and `reactiveVal()` objects. ([#2793](https://github.com/rstudio/shiny/pull/2793))
### Bug fixes
* Fixed [#2606](https://github.com/rstudio/shiny/issues/2606): `debounce()` would not work properly if the code in the reactive expression threw an error on the first run. ([#2652](https://github.com/rstudio/shiny/pull/2652))
@@ -28,6 +30,12 @@ shiny 1.4.0.9001
### Documentation Updates
shiny 1.4.0.1
===========
Minor patch release to account for changes to the grid package that will be upcoming in the R 4.0 release ([#2776](https://github.com/rstudio/shiny/pull/2776)).
shiny 1.4.0
===========

View File

@@ -80,7 +80,6 @@ extract <- function(promise) {
MockShinySession <- R6Class(
'MockShinySession',
portable = FALSE,
class = FALSE,
public = list(
#' @field env The environment associated with the session.
env = NULL,

View File

@@ -91,7 +91,9 @@ createSessionProxy <- function(parentSession, ...) {
#' counterServer("counter1")
#' counterServer("counter2")
#' }
#' shinyApp(ui, server)
#' if (interactive()) {
#' shinyApp(ui, server)
#' }
#'
#'
#'
@@ -117,7 +119,9 @@ createSessionProxy <- function(parentSession, ...) {
#' server <- function(input, output, session) {
#' counterServer2("counter", "The current count is: ")
#' }
#' shinyApp(ui, server)
#' if (interactive()) {
#' shinyApp(ui, server)
#' }
#'
#' @export
moduleServer <- function(id, module, session = getDefaultReactiveDomain()) {
@@ -128,7 +132,7 @@ moduleServer <- function(id, module, session = getDefaultReactiveDomain()) {
#' @rdname moduleServer
#' @export
callModule <- function(module, id, ..., session = getDefaultReactiveDomain()) {
if (!inherits(session, "ShinySession") && !inherits(session, "session_proxy")) {
if (!inherits(session, c("ShinySession", "session_proxy", "MockShinySession"))) {
stop("session must be a ShinySession or session_proxy object.")
}
childScope <- session$makeScope(id)

View File

@@ -222,7 +222,7 @@ reactiveVal <- function(value = NULL, label = NULL) {
rv$set(x)
}
},
class = c("reactiveVal", "reactive"),
class = c("reactiveVal", "reactive", "function"),
label = label,
.impl = rv
)
@@ -969,7 +969,7 @@ reactive <- function(x, env = parent.frame(), quoted = FALSE, label = NULL,
if (length(srcref) >= 2) attr(label, "srcref") <- srcref[[2]]
attr(label, "srcfile") <- srcFileOfRef(srcref[[1]])
o <- Observable$new(fun, label, domain, ..stacktraceon = ..stacktraceon)
structure(o$getValue, observable = o, class = c("reactiveExpr", "reactive"))
structure(o$getValue, observable = o, class = c("reactiveExpr", "reactive", "function"))
}
# Given the srcref to a reactive expression, attempts to figure out what the

View File

@@ -889,6 +889,14 @@ find_panel_info_non_api <- function(b, ggplot_format) {
})
}
# Use public API for getting the unit's type (grid::unitType(), added in R 4.0)
# https://github.com/wch/r-source/blob/f9b8a42/src/library/grid/R/unit.R#L179
getUnitType <- function(u) {
tryCatch(
get("unitType", envir = asNamespace("grid"))(u),
error = function(e) attr(u, "unit", exact = TRUE)
)
}
# Given a gtable object, return the x and y ranges (in pixel dimensions)
find_panel_ranges <- function(g, res) {
@@ -904,11 +912,11 @@ find_panel_ranges <- function(g, res) {
if (inherits(x, "unit.list")) {
# For ggplot2 <= 1.0.1
vapply(x, FUN.VALUE = logical(1), function(u) {
isTRUE(attr(u, "unit", exact = TRUE) == "null")
isTRUE(getUnitType(u) == "null")
})
} else {
# For later versions of ggplot2
attr(x, "unit", exact = TRUE) == "null"
getUnitType(x) == "null"
}
}
@@ -948,7 +956,11 @@ find_panel_ranges <- function(g, res) {
# The plotting panels all are 'null' units.
null_sizes <- rep(NA_real_, length(rel_sizes))
null_sizes[null_idx] <- as.numeric(rel_sizes[null_idx])
# Workaround for `[.unit` forbidding zero-length subsets
# https://github.com/wch/r-source/blob/f9b8a42/src/library/grid/R/unit.R#L448-L450
if (length(null_idx)) {
null_sizes[null_idx] <- as.numeric(rel_sizes[null_idx])
}
# Total size allocated for panels is the total image size minus absolute
# (non-panel) elements.

View File

@@ -207,7 +207,7 @@ reference:
desc: Functions for modularizing Shiny apps
contents:
- NS
- callModule
- moduleServer
- title: Embedding
desc: Functions that are intended for third-party packages that embed Shiny applications.
contents:

View File

@@ -88,6 +88,7 @@ s$setInputs(x=1, y=2)
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-reactlog"></a>}}
\if{latex}{\out{\hypertarget{method-reactlog}{}}}
\subsection{Method \code{reactlog()}}{
No-op
\subsection{Usage}{
@@ -104,6 +105,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-incrementBusyCount"></a>}}
\if{latex}{\out{\hypertarget{method-incrementBusyCount}{}}}
\subsection{Method \code{incrementBusyCount()}}{
No-op
\subsection{Usage}{
@@ -113,6 +115,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-new"></a>}}
\if{latex}{\out{\hypertarget{method-new}{}}}
\subsection{Method \code{new()}}{
Create a new MockShinySession
\subsection{Usage}{
@@ -122,6 +125,7 @@ Create a new MockShinySession
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onFlush"></a>}}
\if{latex}{\out{\hypertarget{method-onFlush}{}}}
\subsection{Method \code{onFlush()}}{
Define a callback to be invoked before a reactive flush
\subsection{Usage}{
@@ -140,6 +144,7 @@ Define a callback to be invoked before a reactive flush
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onFlushed"></a>}}
\if{latex}{\out{\hypertarget{method-onFlushed}{}}}
\subsection{Method \code{onFlushed()}}{
Define a callback to be invoked after a reactive flush
\subsection{Usage}{
@@ -158,6 +163,7 @@ Define a callback to be invoked after a reactive flush
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onEnded"></a>}}
\if{latex}{\out{\hypertarget{method-onEnded}{}}}
\subsection{Method \code{onEnded()}}{
Define a callback to be invoked when the session ends
\subsection{Usage}{
@@ -174,6 +180,7 @@ Define a callback to be invoked when the session ends
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-isEnded"></a>}}
\if{latex}{\out{\hypertarget{method-isEnded}{}}}
\subsection{Method \code{isEnded()}}{
Returns \code{FALSE} if the session has not yet been closed
\subsection{Usage}{
@@ -183,6 +190,7 @@ Returns \code{FALSE} if the session has not yet been closed
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-isClosed"></a>}}
\if{latex}{\out{\hypertarget{method-isClosed}{}}}
\subsection{Method \code{isClosed()}}{
Returns \code{FALSE} if the session has not yet been closed
\subsection{Usage}{
@@ -192,6 +200,7 @@ Returns \code{FALSE} if the session has not yet been closed
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-close"></a>}}
\if{latex}{\out{\hypertarget{method-close}{}}}
\subsection{Method \code{close()}}{
Closes the session
\subsection{Usage}{
@@ -201,6 +210,7 @@ Closes the session
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-cycleStartAction"></a>}}
\if{latex}{\out{\hypertarget{method-cycleStartAction}{}}}
\subsection{Method \code{cycleStartAction()}}{
Unsophisticated mock implementation that merely invokes
the given callback immediately.
@@ -218,6 +228,7 @@ the given callback immediately.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-fileUrl"></a>}}
\if{latex}{\out{\hypertarget{method-fileUrl}{}}}
\subsection{Method \code{fileUrl()}}{
Base64-encode the given file. Needed for image rendering.
\subsection{Usage}{
@@ -238,6 +249,7 @@ Base64-encode the given file. Needed for image rendering.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-setInputs"></a>}}
\if{latex}{\out{\hypertarget{method-setInputs}{}}}
\subsection{Method \code{setInputs()}}{
Sets reactive values associated with the \code{session$inputs} object
and flushes the reactives.
@@ -264,6 +276,7 @@ s$setInputs(x=1, y=2)
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-.scheduleTask"></a>}}
\if{latex}{\out{\hypertarget{method-.scheduleTask}{}}}
\subsection{Method \code{.scheduleTask()}}{
An internal method which shouldn't be used by others.
\subsection{Usage}{
@@ -282,6 +295,7 @@ An internal method which shouldn't be used by others.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-elapse"></a>}}
\if{latex}{\out{\hypertarget{method-elapse}{}}}
\subsection{Method \code{elapse()}}{
Simulate the passing of time by the given number of milliseconds.
\subsection{Usage}{
@@ -298,6 +312,7 @@ Simulate the passing of time by the given number of milliseconds.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-.now"></a>}}
\if{latex}{\out{\hypertarget{method-.now}{}}}
\subsection{Method \code{.now()}}{
An internal method which shouldn't be used by others.
\subsection{Usage}{
@@ -307,6 +322,7 @@ An internal method which shouldn't be used by others.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-defineOutput"></a>}}
\if{latex}{\out{\hypertarget{method-defineOutput}{}}}
\subsection{Method \code{defineOutput()}}{
An internal method which shouldn't be used by others.
\subsection{Usage}{
@@ -327,6 +343,7 @@ An internal method which shouldn't be used by others.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getOutput"></a>}}
\if{latex}{\out{\hypertarget{method-getOutput}{}}}
\subsection{Method \code{getOutput()}}{
An internal method which shouldn't be used by others.
\subsection{Usage}{
@@ -343,6 +360,7 @@ An internal method which shouldn't be used by others.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-registerDataObj"></a>}}
\if{latex}{\out{\hypertarget{method-registerDataObj}{}}}
\subsection{Method \code{registerDataObj()}}{
No-op
\subsection{Usage}{
@@ -363,6 +381,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-allowReconnect"></a>}}
\if{latex}{\out{\hypertarget{method-allowReconnect}{}}}
\subsection{Method \code{allowReconnect()}}{
No-op
\subsection{Usage}{
@@ -379,6 +398,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-reload"></a>}}
\if{latex}{\out{\hypertarget{method-reload}{}}}
\subsection{Method \code{reload()}}{
No-op
\subsection{Usage}{
@@ -388,6 +408,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-resetBrush"></a>}}
\if{latex}{\out{\hypertarget{method-resetBrush}{}}}
\subsection{Method \code{resetBrush()}}{
No-op
\subsection{Usage}{
@@ -404,6 +425,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-sendCustomMessage"></a>}}
\if{latex}{\out{\hypertarget{method-sendCustomMessage}{}}}
\subsection{Method \code{sendCustomMessage()}}{
No-op
\subsection{Usage}{
@@ -422,6 +444,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-sendBinaryMessage"></a>}}
\if{latex}{\out{\hypertarget{method-sendBinaryMessage}{}}}
\subsection{Method \code{sendBinaryMessage()}}{
No-op
\subsection{Usage}{
@@ -440,6 +463,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-sendInputMessage"></a>}}
\if{latex}{\out{\hypertarget{method-sendInputMessage}{}}}
\subsection{Method \code{sendInputMessage()}}{
No-op
\subsection{Usage}{
@@ -458,6 +482,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-setBookmarkExclude"></a>}}
\if{latex}{\out{\hypertarget{method-setBookmarkExclude}{}}}
\subsection{Method \code{setBookmarkExclude()}}{
No-op
\subsection{Usage}{
@@ -474,6 +499,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getBookmarkExclude"></a>}}
\if{latex}{\out{\hypertarget{method-getBookmarkExclude}{}}}
\subsection{Method \code{getBookmarkExclude()}}{
No-op
\subsection{Usage}{
@@ -483,6 +509,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onBookmark"></a>}}
\if{latex}{\out{\hypertarget{method-onBookmark}{}}}
\subsection{Method \code{onBookmark()}}{
No-op
\subsection{Usage}{
@@ -499,6 +526,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onBookmarked"></a>}}
\if{latex}{\out{\hypertarget{method-onBookmarked}{}}}
\subsection{Method \code{onBookmarked()}}{
No-op
\subsection{Usage}{
@@ -515,6 +543,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-doBookmark"></a>}}
\if{latex}{\out{\hypertarget{method-doBookmark}{}}}
\subsection{Method \code{doBookmark()}}{
No-op
\subsection{Usage}{
@@ -524,6 +553,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onRestore"></a>}}
\if{latex}{\out{\hypertarget{method-onRestore}{}}}
\subsection{Method \code{onRestore()}}{
No-op
\subsection{Usage}{
@@ -540,6 +570,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onRestored"></a>}}
\if{latex}{\out{\hypertarget{method-onRestored}{}}}
\subsection{Method \code{onRestored()}}{
No-op
\subsection{Usage}{
@@ -556,6 +587,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-exportTestValues"></a>}}
\if{latex}{\out{\hypertarget{method-exportTestValues}{}}}
\subsection{Method \code{exportTestValues()}}{
No-op
\subsection{Usage}{
@@ -565,6 +597,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getTestSnapshotUrl"></a>}}
\if{latex}{\out{\hypertarget{method-getTestSnapshotUrl}{}}}
\subsection{Method \code{getTestSnapshotUrl()}}{
No-op
\subsection{Usage}{
@@ -592,6 +625,7 @@ No-op
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-ns"></a>}}
\if{latex}{\out{\hypertarget{method-ns}{}}}
\subsection{Method \code{ns()}}{
Returns the given id prefixed by \verb{mock-session-}.
\subsection{Usage}{
@@ -608,6 +642,7 @@ Returns the given id prefixed by \verb{mock-session-}.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-flushReact"></a>}}
\if{latex}{\out{\hypertarget{method-flushReact}{}}}
\subsection{Method \code{flushReact()}}{
Trigger a reactive flush right now.
\subsection{Usage}{
@@ -617,6 +652,7 @@ Trigger a reactive flush right now.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-makeScope"></a>}}
\if{latex}{\out{\hypertarget{method-makeScope}{}}}
\subsection{Method \code{makeScope()}}{
Create and return a namespace-specific session proxy.
\subsection{Usage}{
@@ -633,6 +669,7 @@ Create and return a namespace-specific session proxy.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-clone"></a>}}
\if{latex}{\out{\hypertarget{method-clone}{}}}
\subsection{Method \code{clone()}}{
The objects of this class are cloneable with this method.
\subsection{Usage}{

View File

@@ -5,7 +5,9 @@
\alias{NS}
\alias{ns.sep}
\title{Namespaced IDs for inputs/outputs}
\format{An object of class \code{character} of length 1.}
\format{
An object of class \code{character} of length 1.
}
\usage{
NS(namespace, id = NULL)

View File

@@ -74,6 +74,7 @@ shinyApp(ui, server)
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-new"></a>}}
\if{latex}{\out{\hypertarget{method-new}{}}}
\subsection{Method \code{new()}}{
Creates a new progress panel (but does not display it).
\subsection{Usage}{
@@ -107,6 +108,7 @@ is for backward-compatibility).}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-set"></a>}}
\if{latex}{\out{\hypertarget{method-set}{}}}
\subsection{Method \code{set()}}{
Updates the progress panel. When called the first time, the
progress panel is displayed.
@@ -134,6 +136,7 @@ relative to \code{message}.}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-inc"></a>}}
\if{latex}{\out{\hypertarget{method-inc}{}}}
\subsection{Method \code{inc()}}{
Like \code{set}, this updates the progress panel. The difference
is that \code{inc} increases the progress bar by \code{amount}, instead of
@@ -161,6 +164,7 @@ relative to \code{message}.}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getMin"></a>}}
\if{latex}{\out{\hypertarget{method-getMin}{}}}
\subsection{Method \code{getMin()}}{
Returns the minimum value.
\subsection{Usage}{
@@ -170,6 +174,7 @@ Returns the minimum value.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getMax"></a>}}
\if{latex}{\out{\hypertarget{method-getMax}{}}}
\subsection{Method \code{getMax()}}{
Returns the maximum value.
\subsection{Usage}{
@@ -179,6 +184,7 @@ Returns the maximum value.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getValue"></a>}}
\if{latex}{\out{\hypertarget{method-getValue}{}}}
\subsection{Method \code{getValue()}}{
Returns the current value.
\subsection{Usage}{
@@ -188,6 +194,7 @@ Returns the current value.
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-close"></a>}}
\if{latex}{\out{\hypertarget{method-close}{}}}
\subsection{Method \code{close()}}{
Removes the progress panel. Future calls to \code{set} and
\code{close} will be ignored.
@@ -198,6 +205,7 @@ Removes the progress panel. Future calls to \code{set} and
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-clone"></a>}}
\if{latex}{\out{\hypertarget{method-clone}{}}}
\subsection{Method \code{clone()}}{
The objects of this class are cloneable with this method.
\subsection{Usage}{

View File

@@ -67,7 +67,9 @@ server <- function(input, output, session) {
counterServer("counter1")
counterServer("counter2")
}
shinyApp(ui, server)
if (interactive()) {
shinyApp(ui, server)
}
@@ -93,7 +95,9 @@ ui <- fluidPage(
server <- function(input, output, session) {
counterServer2("counter", "The current count is: ")
}
shinyApp(ui, server)
if (interactive()) {
shinyApp(ui, server)
}
}
\seealso{

View File

@@ -1,5 +1,11 @@
context("reactivity")
test_that("reactive and reactiveVal are functions", {
expect_s3_class(reactive({1}), "function")
expect_s3_class(reactiveVal(1), "function")
})
test_that("ReactiveVal", {
val <- reactiveVal()
@@ -1097,6 +1103,10 @@ test_that("event handling helpers take correct dependencies", {
})
run_debounce_throttle <- function(do_priming) {
# Some of the CRAN test machines are heavily loaded and so the timing for
# these tests isn't reliable. https://github.com/rstudio/shiny/pull/2789
skip_on_cran()
# The changing of rv$a will be the (chatty) source of reactivity.
rv <- reactiveValues(a = 0)