Free Tutorial — How to use React with webpacker and Rails 5.1

This is a new lesson from The FREE Complete React on Rails Course. Check out the full course and learn how to use React with Rails in a few hours for free.

Rails 5.1 shipped with native support for Webpack and therefore, React, Angular, Vue.js and other libraries, through the webpacker gem.

In this lesson, we will see how to use React in a Rails app without using gems like react-rails or react_on_rails.

We will modify an existing Rails 5.0 app, which uses react-rails, to use the webpacker gem instead. The app is a calendar appointments app, in which you can create appointments with a title and appointment date and time, as shown in the screenshot below.

Calendar appointments app from The Free React on Rails course

The starting point code with react-rails is here and the final code with webpacker is here:

First, we need to install Node.js and yarn.

You can install Node by downloading the binary for your platform from the official website.

For installing yarn, see the official documentation. On Max OS X you can install it with brew:

brew install yarn

Now let’s change our calendar appointments app to use webpacker.

Since our app is using Rails 5.0, we’ll need to install the webpacker gem (which supports Rails versions back to 4.2).

(If you want to learn how to create a brand new Rails 5.1 app with React support out of the box, see the section on that below.)

First, let’s remove the react-rails gem from the Gemfile and run bundle.

Also, remove this line from config/application.rb:

config.react.addons = true

Now, let’s add React support to our existing Rails app by installing the webpacker gem first. Add the following line to the Gemfile:

gem 'webpacker'

Then run:

bundle install

Then run the webpacker install script:

$ ./bin/rails webpacker:install

and then run the React install script:

$ ./bin/rails webpacker:install:react

The installer will add all relevant dependencies using yarn, some changes to configuration files and create a new app/javascript/packs directory from where Webpack will compile any Javascript or CSS, including React components.

The installer also creates an example React component file called hello_react.jsx in app/javascript/packs.

We can use React components from this directory in a view by using the javascript_pack_tag helper method. For example:

<%= javascript_pack_tag ‘hello_react’ %>

Now let’s move our Calreact app components from the app/assets/javascript/components directory into the new app/javascript/packs directory.

Also move utils.js to the same directory.

We can structure the files under this directory in any way we like, as long as we import them correctly. But for this lesson, let’s just put them directly in the packs directory.

We need to rename the files — remove the .es6 extension and name them simply with a .jsx extension.

Remove react files, moment, react-datetime and components from application.js:

//= require react
//= require react_ujs
//= require moment
//= require react-datetime.min
//= require components

Also delete the files components.js, moment.js and react-datetime.min.js from the assets directories. We also don’t need the components directory any more.

Install moment and react-datetime using yarn:

$ yarn add moment
$ yarn add react-datetime

One important change from using react-rails is that we need to explicitly export and import any libraries and code we use inside across files.

So let’s add import statements to components.

Note: The imports in curly braces are named imports, where the imported module has been exported as a named const. The imports without curly braces are for modules which are default exports.

In appointments.jsx:

import React from ‘react’
import ReactDOM from ‘react-dom’
import AppointmentForm from ‘./appointment_form’
import { AppointmentsList } from ‘./appointments_list’

In appointment_form.jsx:

import React from ‘react’
import Datetime from ‘react-datetime’

In appointments_list.jsx:

import React from ‘react’
import { Appointment } from ‘./appointment’

In appointment.jsx:

import React from ‘react’
import moment from ‘moment’
import { formatDate } from './utils'

In utils.js

import moment from ‘moment’

And we also need to export the components and functions:

In utils.js:

export const formatDate = function(d) {

Note: You can also export the const as a default instead after defining it and then import it without curly braces wherever you need it:

export default formatDate

In appointments.jsx:

export default class Appointments extends React.Component {

In appointment_form.jsx:

export default class AppointmentForm extends React.Component {

In appointments_list.jsx:

export const AppointmentsList = ({appointments}) =>

In appointment.jsx:

export const Appointment = ({appointment}) =>

React addons are now deprecated, so we need to install immutability-helper for immutable updates:

$ yarn add immutability-helper

Then import it where we need it in appointments.jsx:

import update from ‘immutability-helper’

And change React.addons.update simply to update in appointments.jsx:

addNewAppointment (appointment) {
const appointments = update(this.state.appointments, { $push: [appointment]});

In appointments.jsx, replace the react_component helper method with:

#appointments_data{data: @appointments.to_json}
= javascript_pack_tag ‘appointments’

This will put the appointments data in the data attribute of a div with id appointments_data on the page. But we still need to pass it to our React component.

To do that, we need to add the following code to our appointments component:

In appointments.jsx:

document.addEventListener(‘DOMContentLoaded’, () => {
const node = document.getElementById(‘appointments_data’)
const data = JSON.parse(node.getAttribute(‘data’))
ReactDOM.render(
<Appointments appointments={data} />,
document.body.appendChild(document.createElement(‘div’)),
)
})

The react_component helper method provided by react-rails (and react_on_rails) does this for us behind the scenes. If you wish to use it, you can do so by using the webpacker-react gem.

Now that we are using Webpack, we can also use CSS imports for our React components instead of relying on the asset pipeline.

Let’s remove the react-datetime CSS file from the vendor assets folder and instead import it from the already installed npm package in the node_modules directory in the root of the app.

In appointment_form.jsx:

import ‘react-datetime/css/react-datetime’

We also need to use the stylesheet_pack_tag helper method to make the CSS import work. Add this line in appointments/index.html.haml:

= stylesheet_pack_tag ‘appointments’

Finally, we’ve made all the changes we need and can now run the app.

Run the Rails server:

$ rails s

We also need to run Webpack dev server to serve our React components:

$ ./bin/webpack-dev-server

Now our updated calendar appointments app will run on port 3000 and Webpack will serve our React components from port 8080.

If you get an error saying ‘obj not defined’, change this line in the handleChange method in appointment_form.jsx:

obj = {};

to:

const obj = {};

Using React with a new Rails 5.1 app

Instead of upgrading an app running an older version of Rails, you can also start with a new Rails 5.1 app with webpack React support out of the box. First make sure you have the Rails gem version 5.1 installed.

gem install rails -v 5.1

Then we can create a new Rails 5.1 app with React support like so:

$ rails new calreact --webpack=react

To build the calendar appointments app, in addition to following the steps above to change the React code, we’ll also need to add all the other code for the app — the model, controller, and database migrations.

This is a lesson from The FREE Complete React on Rails Course, where I will teach you how to be a pro at using React with Rails, while building some fun stuff.