Skip to content

Commit 9b7f74b

Browse files
Merge pull request #24 from cpsievert/edits
Some edits for the Shiny inputs vignette
2 parents 992dfbd + 56d28b6 commit 9b7f74b

File tree

1 file changed

+42
-46
lines changed

1 file changed

+42
-46
lines changed

vignettes/intro_inputs.Rmd

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Authoring inputs powered by React with reactR"
33
author:
4-
- Alan Dipert
4+
- Alan Dipert and Carson Sievert
55
date: "`r Sys.Date()`"
66
output: rmarkdown::html_vignette
77
vignette: >
@@ -70,21 +70,22 @@ provide the templating for creating an input powered by the
7070
`react-color` library on npm:
7171

7272
```{r}
73-
# Create the R package
74-
usethis::create_package("~/colorpicker")
73+
# Create the R package (rstudio=TRUE is recommended if you're not already comfortable with your terminal)
74+
usethis::create_package("~/colorpicker", rstudio = TRUE)
7575
# Scaffold initial input implementation files
7676
withr::with_dir(
7777
"~/colorpicker",
7878
reactR::scaffoldReactShinyInput("colorpicker", list("react-color" = "^2.17.0"), edit = FALSE)
7979
)
8080
```
8181

82+
8283
## Building and installing
8384

8485
### Building the JavaScript
8586

8687
The next step is to navigate to the newly-created `colorpicker` project and run
87-
the following commands in the terminal:
88+
the following commands in the terminal. If you're new the terminal, we recommend opening your newly created RStudio `~/colorpicker/colorpicker.Rproj` project file, then running the following in the [RStudio terminal tab](https://support.rstudio.com/hc/en-us/articles/115010737148-Using-the-RStudio-Terminal):
8889

8990
```
9091
yarn install
@@ -172,38 +173,42 @@ accomplish these, `react-color` components can [optionally
172173
take](http://casesandberg.github.io/react-color/#api) the following
173174
[props](https://reactjs.org/docs/components-and-props.html):
174175

175-
* `color`: accepts a string of a hex color like `'#333'`
176-
* `onChangeComplete`: accepts a function taking a single argument, the new
177-
color, that will be called when the new color is selected
178-
179-
These operations are conceptually similar enough to the API expected of Shiny
180-
inputs that `reactR` can assist with integrating React components into Shiny
181-
as inputs.
182-
183-
It does so by introducing a convention for wrapping components like those
184-
provided by `react-color` with an intermediate component that accepts these
185-
props:
186-
187-
* `configuration`: A configuration object containing data from R used to
188-
parameterize the input's behavior
189-
* `value`: The input's values over time, beginning with the default
190-
* `setValue`: A function to call with the input's new value when one is created
191-
192-
The `configuration` and `value` props are initially populated on the R side, as
193-
arguments to the `createReactShinyInput` function inside the input's constructor
194-
function. In the case of our newly-scaffolded input, that happens in
195-
`R/colorpicker.R`.
196-
197-
The `setValue` function is what causes new values to be sent to R, and also what
198-
triggers the "intermediate" component to repaint itself.
176+
* [`color`](http://casesandberg.github.io/react-color/#api-color): accepts a
177+
string of a hex color like `'#333'`
178+
* [`onChangeComplete`](http://casesandberg.github.io/react-color/#api-onChangeComplete):
179+
accepts a JavaScript function taking a single argument, the new `color`, that
180+
will be called when the new color is selected
181+
182+
Since this React component calls a configurable function (i.e., `onChangeComplete`) when the input (i.e., color) value changes, we can supply a function to inform Shiny about these changes. You could, in theory, do this by writing your own custom Shiny input wrapper around this component, but `reactR` provides some conventions to make it much easier. These conventions have two main parts (R and JavaScript):
183+
184+
1. Use `reactR::createReactShinyInput()` to construct the user-facing R input and route any user-supplied options (e.g., the `default` input value and other `configuration`) to the React component. This part was already done for us in the `R/colorpicker.R` file of our colorpicker project:
185+
186+
```r
187+
colorpickerInput <- function(inputId, default = "") {
188+
reactR::createReactShinyInput(
189+
inputId = inputId,
190+
class = "colorpicker",
191+
dependencies = htmltools::htmlDependency(
192+
name = "colorpicker-input",
193+
version = "1.0.0",
194+
src = "www/colorpicker/colorpicker",
195+
package = "colorpicker",
196+
script = "colorpicker.js"
197+
),
198+
default = default,
199+
configuration = list(),
200+
container = htmltools::tags$span
201+
)
202+
}
203+
```
199204

200-
So, in order to make the components delivered by `react-color` accessible on the
201-
R side, we must create our own intermediate component that wraps one of
202-
`react-color`'s pickers.
205+
2. Design an *intermediate* React component that routes information from `colorpickerInput()` to the `<SketchPicker>` component and also inform Shiny when a new color is chosen. This intermediate component should be a [functional component](https://reactjs.org/docs/components-and-props.html#function-and-class-components) with three arguments:
203206

204-
### Create intermediate component
207+
* `configuration`: The JSON equivalent of the `configuration` argument from `reactR::createReactShinyInput()`. In this particular example, `configuration` isn't used.
208+
* `value`: The input's values over time, beginning with the `default` supplied from `reactR::createReactShinyInput()`.
209+
* `setValue`: A JavaScript function to call with the input's new value when one is created. This function is not user supplied, but rather an internal hook for informing Shiny about changes to the component's current state (i.e. value).
205210

206-
Open `srcjs/colorpicker.jsx` and paste the following in:
211+
Consider the following intermediate component, `PickerInput`. Note how this intermediate component allows one to set the default `value` from R and also calls `setValue()` inside `onChangeComplete` in order to inform Shiny about new color values. Finally, `reactR.reactShinyInput()` registers this intermediate component as a custom Shiny input binding named `colorpicker`.
207212

208213
```js
209214
import { reactShinyInput } from 'reactR';
@@ -218,22 +223,13 @@ const PickerInput = ({ configuration, value, setValue }) => {
218223
);
219224
};
220225

226+
// Note the first argument here should match the `class`
227+
// argument of the reactR::createReactShinyInput() from step 1
221228
reactShinyInput('.colorpicker', 'colorpicker', PickerInput);
222229
```
223230

224-
The above code creates a new [function
225-
component](https://reactjs.org/docs/components-and-props.html#function-and-class-components)
226-
called `PickerInput` that expects the props supplied by reactR and renders a
227-
parameterized `SketchPicker` from `react-color`. The `configuration` value is
228-
not yet used.
229-
230-
After saving the file, run `yarn run webpack` in the terminal and rebuild the
231-
package.
232-
233-
## Trying it out
234-
235-
After rebuilding the JavaScript and the package, try running `app.R` again. You
236-
should see something like this:
231+
Open the `srcjs/colorpicker.jsx` file in your colorpicker project and paste this code into it. After saving the file, run `yarn run webpack` in the terminal, re-install the
232+
package, then run `shiny::runApp()` again
237233

238234
<video autoplay muted>
239235
<source src="./input_sketchpicker.mp4"/>

0 commit comments

Comments
 (0)