Skip to content

Instantly share code, notes, and snippets.

@drnic
Created June 15, 2023 23:37
Show Gist options
  • Save drnic/b1987712713906b99f5e1357d6063909 to your computer and use it in GitHub Desktop.
Save drnic/b1987712713906b99f5e1357d6063909 to your computer and use it in GitHub Desktop.
In Rails apps using StimulusJS, load React components found at app/javascript/react/*/index.tsx, and make them available via Ruby helper react(name)
import React from "react";
const Hello = ({ name }: { name: string }) => <span>Hello {name}</span>;
Hello.defaultProps = { name: "World" }
export default Hello;
<div class="py-32 max-w-2xl m-auto text-center flex flex-col items-center justify-center">
<h1 class="mb-2">Welcome to React on Rails</h1>
<div id="hellos" class="my-4 bg-white p-4 border border-gray-200 rounded">
<%= react("Hello") %>
<%= react("Hello", props: {name: "Dr Nic"}) %>
</div>
<%= button_to "Add", send_react_component_path, class: "btn btn-primary" %>
</div>
import { Controller } from "@hotwired/stimulus"
import React from "react"
import ReactDOM from "react-dom/client"
import modulePaths from "../react/**/index.tsx"
const modules = {}
// Snazzy code written by Marco Roth on discord
const capitalize = string => string.charAt(0).toUpperCase() + string.slice(1)
const camelize = string => string.replace(/(?:[_-])([a-z0-9])/g, (_, char) => char.toUpperCase())
modulePaths.forEach((file) => {
const name = file.filename.split("/").reverse()[1]
const identifier = capitalize(camelize(name))
if (!modules.hasOwnProperty(identifier)) {
modules[identifier] = file.module.default
}
})
export default class extends Controller {
static values = {
component: String,
props: Object
}
connect() {
const module = modules[this.componentValue]
if (module) {
this.root = ReactDOM.createRoot(this.element)
this.root.render(
React.createElement(module, this.propsValue)
)
} else {
console.error(`Could not find module ${this.componentValue}`)
}
}
disconnect() {
this.root.unmount()
}
}
module ReactHelper
def react(component_name, props: {}, **args)
content_tag(:div, "", data: {
controller: "react",
react_component_value: component_name,
react_props_value: props
}, **args)
end
end
<%= turbo_stream.append "hellos",
react("Hello", props: {name: Faker::Name.first_name}) %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment