← notes

Mounting React inside Rails, and the initial-state seam

Mar 26, 2021

A cryptocurrency portfolio tracker, built as Rails with React inside it.

app/javascript/components/ holds App, Portfolio, PortfolioContainer, PortfolioItem, Search, SearchResult and Calculate, mounted from a Webpacker pack, with currencies_controller.rb serving JSON. This was the standard shape before Hotwire, and it has one seam every project of the kind must solve.

The seam is initial state. A React tree mounted in a Rails view starts empty and has to get data from somewhere. Fetching on mount is obvious and means the user sees an empty shell, then a spinner, then content, on a page the server could have rendered complete. Passing a props payload into the mount point avoids that and costs a second serialization path that has to stay in sync with the JSON API.

Then routing, which has to belong to one of them. Rails routing with React islands is coherent. React Router inside a Rails app is coherent. Both at once gives URLs that work when clicked and break on refresh.

CSRF is the small one that bites everyone: Rails wants a token on non-GET requests and fetch does not send it unless you read it from the meta tag. The failure is a 422 that says nothing useful.

Hotwire makes most of this unnecessary now.