vignettes/tutorial/use-react-in-rhino.Rmd
use-react-in-rhino.RmdThis tutorial will show you how to seamlessly use React components in your Rhino application. It assumes that you already have some experience with React, the popular JavaScript library for creating web interfaces.
Familiarity with shiny.react,
or with packages based on it (shiny.fluent,
shiny.blueprint)
will be helpful, but it is not a requirement.
Before starting make sure that you have installed:
install.packages("rhino").To start off, let’s initialize a fresh Rhino application. Launch the R console in an empty directory and run:
rhino::init()To use React in Rhino we need to add the shiny.react
package to our project
dependencies:
rhino::pkg_install("shiny.react")Now, there are three steps to add a React component to your Rhino application:
Let’s go through these steps to add a simple Reveal
component to our app.
We will use JSX, a syntax
extension for JavaScript, to define our component. Create a
Reveal.jsx file in the app/js directory with
the following content:
const { useState } = React;
export default function Reveal({ id, children }) {
const [visible, setVisible] = useState(false);
return (
<div id={id}>
<button type="button" onClick={() => setVisible(!visible)}>
{visible ? 'Hide' : 'Show'}
</button>
{visible && children}
</div>
);
}The Reveal component is just a <div>
with the provided ID, and a button which can be used to show or hide its
children.
To make this component available for Rhino, we need to register it.
Edit the app/js/index.js file like so:
Rhino is a global variable which can be used without any
declaration, similar to Shiny. The
registerReactComponents() function takes an object mapping
component names to their definitions ({ Reveal } is a
shorthand for { Reveal: Reveal }).
Lastly, we need to build our JavaScript:
rhino::build_js()This will create the app/static/js/app.min.js file which
will be automatically included by Rhino.
Declaring the component simply means creating a function which will
allow us to use the component in R. Let’s create a new
react.R file in the app/view directory:
box::use(
rhino[react_component],
)
#' @export
Reveal <- react_component("Reveal")The name passed to rhino::react_component() has to match
the name used in the call to registerReactComponents() in
the previous step.
Let’s use our Reveal component to wrap the entire UI of
our application. Edit the app/main.R file like so:
box::use(
shiny[bootstrapPage, div, moduleServer, NS, renderUI, tags, uiOutput],
)
box::use(
app/view/react[Reveal], # Import the component.
)
#' @export
ui <- function(id) {
ns <- NS(id)
bootstrapPage(
# Use the component.
Reveal(
# Named arguments become props.
id = ns("reveal"),
# Unnamed arguments become children.
uiOutput(ns("message"))
)
)
}
#' @export
server <- function(id) {
moduleServer(id, function(input, output, session) {
output$message <- renderUI({
div(
style = "display: flex; justify-content: center; align-items: center; height: 100vh;",
tags$h1(
tags$a("Check out Rhino docs!", href = "https://appsilon.github.io/rhino/")
)
)
})
})
}Reveal is a function representing our component. Named
arguments will be passed to the component as props, while unnamed
arguments will become its children.
The return value of the Reveal function is a
shiny.tag object. It can be used in the UI definition of
your application, or rendered dynamically using either
shiny::renderUI() or
shiny.react::renderReact(). This object behaves much like
vanilla Shiny components and can be freely mixed with them, as the
example illustrates.
We can now run the application and see our component in action:
shiny::runApp()As a bonus, let’s write a Cypress end-to-end test to check if our
component works as expected. Edit the
tests/cypress/e2e/app.cy.js file as follows:
describe('app', () => {
beforeEach(() => {
cy.visit('/')
})
it('works with React components', () => {
cy.get('#app-reveal button').click();
cy.get('#app-reveal').contains('Check out Rhino docs!');
})
})This code tells Cypress to click the button found in the element with
ID #app-reveal, and then to verify that it contains a
Check out Rhino docs! string. To run this test we can
use:
rhino::test_e2e()You can learn more about Cypress tests in our Tutorial: Write end-to-end tests with Cypress.
After this tutorial you should know how to add React components to
your Rhino application. To get a deeper understanding of the underlying
mechanism, take a look at shiny.react
tutorial.