How to use React inside Ruby on Rails

Hrishi Mittal
 
There are a few different ways of using React inside Ruby on Rails apps. With the recent improvements in native support in Rails for JavaScript tooling, it’s now easier than ever to start using JavaScript libraries, including React, with Rails.

In this course, we'll look at four ways:

  1. webpacker

  2. react-rails

  3. react_on_rails

  4. Separate frontend React app with a Rails API

Initially, we are going to focus on using React inside Rails with webpacker and later on using React in a separate frontend app with a Rails API.

We’ll place less emphasis on the other two methods using third party gems. But let’s have a quick look at the first three methods in this lesson.

This tutorial is based on Ruby 2.6.5 and the latest Rails gem (6.0.1 at the time of writing this tutorial). You can install and use Ruby 2.6.5 using Ruby version manager (rvm) like this:

$ rvm install 2.6.5
$ rvm use 2.6.5

You can install Rails 6.0.1 like this:

gem install rails -v=6.0.1

1. webpacker

Create a new Rails app with React support via webpacker:

$ rails new eventlite --webpack=react
This creates a Rails app with Webpack configured and a new directory for storing JavaScript code and a couple of new files:

app/javascript:
  └── packs:
      └── application.js
      └── hello_react.jsx
All files in the new app/javascript/packs directory are compiled by Webpack.

There’s one example React file hello_react.jsx, which defines a simple functional React component called Hello that can display the words “Hello React!” on a page. It can also take a prop called name to display it instead of the word “React”.

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

const Hello = props => (
  <div>Hello {props.name}!</div>
)

Hello.defaultProps = {
  name: 'David'
}

Hello.propTypes = {
  name: PropTypes.string
}

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Hello name="React" />,
    document.body.appendChild(document.createElement('div')),
  )
})
We can use this component on any page by linking it with the javascript_pack_tag helper method.

We’re going to build a simple one-page application for creating and listing events.

So let’s start by creating a new events view file app/views/events/index.html.erb and use the javascript_pack_tag method inside it to display the default example Hello component:

<%= javascript_pack_tag 'hello_react' %>
Let’s create the associated controller and index action for events:

class EventsController < ApplicationController
  def index
  end
end
And make that our root path in config/routes.rb:

root 'events#index'
Then we can start the Rails server:

$ rails server
Go to http://localhost:3000 to see the result:

react-rails is the official React community gem for integrating React with Rails. The main benefit of using this gem is the react_component helper method which makes it easy to pass Rails data to components.

You can use react-rails with webpacker or with Sprockets (to bundle the JSX into the asset pipeline).

a. Using react-rails with webpacker

Add the react-rails gem to the Gemfile of the app we created above and install it:

Gemfile:
gem 'react-rails'

$ bundle install
Then run the react-rails generator:

$ rails generate react:install
This creates the app/javascript/components/ directory for storing your React components. It also sets up configuration for mounting components and server-side rendering.

The gem adds the following lines in application.js to load the gem’s JavaScript code (react_ujs) and all code inside the components directory:

var componentRequireContext = require.context("components", true);
var ReactRailsUJS = require("react_ujs");
ReactRailsUJS.useContext(componentRequireContext);
We can use the same Hello component we created earlier with webpacker by moving it to the new components directory. We also need to rename the file to ‘Hello.jsx’ (case sensitive).

react-rails provides a convenient helper method called react_component to render React components inside views.

First let’s export the component and remove the call to ReactDOM.render on document load. The component code will now look like this:

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

const Hello = props => (
  <div>Hello {props.name}!</div>
)

Hello.defaultProps = {
  name: 'David'
}

Hello.propTypes = {
  name: PropTypes.string
}

export default Hello
And now inside our view file events/index.html.erb, we can replace the javascript_pack_tag with a call to react_component:

<%= react_component("Hello") %>
We can also pass another value for the name prop easily:

<%= react_component("Hello", { name: "react-rails" }) %>

Now if you restart the Rails server, you can see the gem in action in your browser at http://localhost:3000:
Important note: If you're using Rails 5, you'll also need to include the application.js file using the javascript_pack_tag in your application.html.erb layout file. If you already have a javascript_include_tag, replace it with the javascript_pack_tag.

app/views/layouts/application.html.erb:
<head>
  ...
  <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  ...
</head>

Rails 6 automatically adds the javascript_pack_tag, so you don't need to add it manually unless you're using an older version of Rails.

The react-rails gem also provides a component generator to automatically create a basic component by passing it a component name and props (with their proptypes). It’s similar to Rails generators for creating models and scaffolds:

$ rails generate react:component HelloWorld greeting:string
b. Using react-rails with sprockets

react-rails also gives you the option to continue using the default Rails asset pipeline to serve your React code, instead of using webpacker.

You can use this option by installing just the react-rails gem without the webpacker gem, and following the same steps as above.

Note that the webpacker gem is included in Rails by default since version 6. So, for an existing Rails 6 app, you’ll need to uninstall it and move all your JavaScript code to the classic app/assets/javascripts directory. Or you can generate a new Rails app without webpacker by using the –skip-javascript flag:

$ rails new eventlite --skip-javascript
I strongly recommend you avoid this route. It’s best to use the new Rails standard webpacker so that you can get all the benefits of the latest JavaScript tooling and you don’t create legacy code that will get out of date very quickly.

The other most popular third-party gem for integrating React into Rails is the react_on_rails gem created by ShakaCode.

Similar to the react-rails gem, now that Rails already provides an easy way to use React via webpacker, you have to see if the stated benefits of the react_on_rails gem apply to your situation.

The main benefits include better support for server side rendering, easy passing of props to React components (with the react_component method just like react-rails), and Redux and React Router integration.

This gem requires webpacker. To use it in a new Rails app with webpacker, let’s install the gem first.

Add it to to the Gemfile:

gem 'react_on_rails', '11.1.4'
Then run:

$ bundle install
After installing the gem, we must first commit the code to git or the gem’s install generator won’t run. This is an easy step to miss, so make sure you do it before you proceed.

$ git add -A && git commit -m "initial commit"

Once you’ve committed the code to git, run the install generator and start the Rails server:

$ rails generate react_on_rails:install
This generates some example code and configuration and installs some dependencies.

This gem places all React code under a new app/javascript/bundles directory. This is just a convention, you can use other directories if you like.

The gem install generator automatically generates an example component HelloWorld stored in app/javascript/bundles/HelloWorld/components/HelloWorld.jsx.

It also generates a file called hello-world-bundle.js inside the app/javascript/packs directory. This is where the HelloWorld component code is imported and registered with react_on_rails so that it can be used in views.

import ReactOnRails from 'react-on-rails';

import HelloWorld from '../bundles/HelloWorld/components/HelloWorld';

// This is how react_on_rails can see the HelloWorld in the browser.
ReactOnRails.register({
  HelloWorld,
});
react_on_rails also provides a react_component helper method for rendering components inside views and pass props to them. You can see an example in the automatically generated view app/views/hello_world/index.html.erb:

<h1>Hello World</h1>
<%= react_component("HelloWorld", props: @hello_world_props, prerender: false) %>
Start the Rails server and visit http://localhost:3000/hello_world to see the component in action:



That’s a quick overview of 3 ways to get started with using React inside your Rails app.
I recommend starting with webpacker and using other gems only if you need their specific benefits.

Once an app is big and complex enough, a lot of developer teams choose to move their React code into a separate frontend app and use the Rails app as a backend API.

We'll cover this in the "Using React with a Rails API" module of this course later on.