← all posts

Use React in Rails without the react-rails gem

react-rails is a handy gem that helps integrate ReactJS into your Rails application.

While it comes with some great features like server side rendering, bundled UJS, and view/controller helpers, it's a bit heavy for smaller Rails applications or cases where you're mounting simple components.

I have previously covered why it's sometimes a good idea to build your own version of something instead of using an outside library, and this is one of the cases where the simplicity and learning experience outweigh the various features the library brings.

The Approach

  1. Create a server-side (Rails) helper that will create a DOM mount node
  2. Create a client-side (Javascript) helper to mount a Component onto a DOM node

The Rails Side

First we create a helper method that will create a DOM node (a <div>) that we can mount our React component on to.

The helper will assign the DOM node a unique id so the JavaScript code can locate it later. We will also store any props we want to pass to the component as a data-* attribute on the element itself.

All we have to do is call this helper from the view. I've used the name react_component to mirror the name of the view helper that react-rails provides.

The JavaScript Side

Now that the DOM node exists, we can dynamically mount components on to it.

First we create a JS helper function (mountReactComponent()) that does the following

  1. Finds the DOM node from the specified id
  2. Extracts the props from the data-react-props attribute
  3. Mounts the specified component on to the node with React.render()

Once that's set up, it's just a matter of calling mountReactComponent() without our desired example component.

Conclusion

And that's it!

This approach may come with a few limitations as you scale but it does it's main job well: rendering ReactJS components into your page. Coupled with standalone Webpack to bundle assets, I've succesfully used this in several mid-tier apps without many issues for a few years now.