15.2 Reactivity anti-patterns
A invalidates B which invalidates C which invalidates A which invalidates B which invalidates C, and so on…
](images/15-reactivity.png)
Figure 15.1: Reactivity an overview
Too much reactivity can lead to recursive behaviors.
How to handle it:
- example app
- set specific steps
- let the user choose by step
For example in the case of selecting dates:
dateInput()
and the selectInput()
updates each other (cac_1)
One way to solve this is to add some extra logic to the app by:
selectInput()
and adding an the observeEvent(input$year, {})
(cac_2)
15.2.1 observe vs observeEvent
The main guideline is to use observeEvent()
as much as possible, and avoid observe()
as much as possible.
Looking at the steps taken for building this first example app, we see that changing the text input doesn’t make any difference, but if we add the “reverse” opting, we can see the recursive taking action.
In this example we use obeserve()
: (cac_3)

Figure 15.2: Recursivity
How many potential invalidation points we have here?
input$txt
input$rev
input$casefolding
It is safer to go with observeEvent()
, as it allows you to see at a glance the condition under which the content is invalidated and re-evaluated.

Figure 15.3: Recursivity
15.2.2 Building triggers and watchers
- create “flag” objects with an
init
function - trigg these flags with
trigger()
- invalidate these flags to a reactive context, we
watch()
these flags
To solve this kind of issues, ColinFay provides a package: gargoyle package that provides wrappers around {shiny} to turn your app into and event-based application instead of a full reactive app.
The framework is centered around a listen & trigger mechanism.
# CRAN version
# install.pacKages("gargoyle")
# Dev version
# remotes::install_github("ColinFay/gargoyle")
gargoyle::init("this")
initiates a “this” flag: most of the time you will be generating them at the app_server() level.gargoyle::watch("this")
sets the flag inside a reactive context, so that it will be invalidated every time you trigger(“this”) this flag.`gargoyle::trigger(“this”) triggers the flags.
(Example of the implemented structure: {hexmake} (Fay 2021g))
A practical example of the implementation uses an environment to store the value.
So, do not rely on any reactive value invalidating the reactive context, but the result is rendered on when “render2” flag is triggered. (cac_4)