Rails 7 and React Install Guide


I love Rails! I also really like React for complex, interactive components. I’ve found it very product to use Turbo and Stimulus (from Hotwire) with sprinkles of React.

With Rails 7, esbuild is now the default javascript tooling. In the past, I’ve used react-rails but their documentation is still aimed at webpacker based Rails projects. Thankfully, a kind soul found a working setup with esbuild. I took their working example repo and made this step by step guide.

Dependencies

Add gem "react-rails" to your Gemfile.

Add the following to your package.json.

"esbuild-plugin-import-glob": "^0.1.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react_ujs": "^2.6.1",

Install these using your preferred command line tools.

esbuild

Add the following to your esbuild.config.js. Below the existing require statements at the top of the file:

const ImportGlobPlugin = require('esbuild-plugin-import-glob').default;

Next, add ImportGlobPlugin() to the plugins array in your config object. It should look like this after plugins: [rails(), ImportGlobPlugin()],.

Next, add loader: { '.js': 'jsx' }, to your config object.

Components

Create the directory app/javascript/components.

Create a app/javascript/components/index.js file with the following contents:

import components from "./**/*.jsx"

let componentsContext = {}
components.forEach((component) => {
  componentsContext[component.name.replace(".jsx", "")] = component.module.default
})

const ReactRailsUJS = require("react_ujs")

ReactRailsUJS.getConstructor = (name) => {
  return componentsContext[name]
}
ReactRailsUJS.handleEvent('turbo:load', ReactRailsUJS.handleMount, false);
ReactRailsUJS.handleEvent('turbo:frame-load', ReactRailsUJS.handleMount, false);
ReactRailsUJS.handleEvent('turbo:before-render', ReactRailsUJS.handleUnmount, false);

Add import "./components" to application.js.

Create a component to render. Here’s a simple HelloWorld.jsx component you can use:

import React from 'react';

export default function HelloWorld() {
  return <h1>Hello World</h1>;
}

Voila, you can use your component.

react_component "HelloWorld"