Skip to content

Instantly share code, notes, and snippets.

@jwo
Last active April 19, 2020 21:31
Show Gist options
  • Select an option

  • Save jwo/7d9524d9075d129491d810cdf40f34b2 to your computer and use it in GitHub Desktop.

Select an option

Save jwo/7d9524d9075d129491d810cdf40f34b2 to your computer and use it in GitHub Desktop.
register React component on page with turbolinks working. The Rails parts (helper and ERB) are optional, but since this IS turbolinks, you probably ARE using rails.
<h1>Oh Hai</h1>
<%= react_component 'oh-hai' %>
module ApplicationHelper
def react_component(container, props=nil)
content_tag(:div, nil, data: { "react-container": container, "react-props": props })
end
end
import {registerComponent} from 'registerComponent';
import OhHai from 'oh-hai';
document.addEventListener('turbolinks:load', () => registerComponent(OhHai, 'oh-hai'));
import React from 'react'
import ReactDOM from 'react-dom'
export function registerComponent (instance, container) {
const selector = `[data-react-container=${container}]`
let componentEntry = document.querySelector(selector)
if (componentEntry) {
const propsJSON = componentEntry.getAttribute("data-react-props")
const props = propsJSON && JSON.parse(propsJSON)
ReactDOM.render(React.createElement(instance, props),
componentEntry)
}
}
<div data-react-container="oh-hai"></div>
@jwo
Copy link
Copy Markdown
Author

jwo commented Aug 3, 2016

ORRRR, if we wanted to work in Turbolinks and not-turbo-links, maybe we do this in main.js

const domReadyEvent = (typeof TurboLinks !== 'undefined') ? 'turbolinks:load' : 'DOMContentLoaded' 

document.addEventListener(domReadyEvent, () => { 
  registerComponent(OhHai, 'oh-hai'));
  registerComponent(NewsletterSelectContainer, 'newsletter-selection');
}

@jdmorlan
Copy link
Copy Markdown

jdmorlan commented Aug 3, 2016

Yes! I love the last example. More explicit about the event listener being added, but still concise calling registerComponent

@slvtrs
Copy link
Copy Markdown

slvtrs commented Feb 15, 2018

This is a godsend!
I had to add a listener into registerComponent to trigger my components' unmount cycle, and then turbolinks and react finally got along without needing to rely on extra gems.

document.addEventListener('turbolinks:before-render', () => {
  ReactDOM.unmountComponentAtNode(componentEntry)
})

@ingeniousgenius
Copy link
Copy Markdown

I modified mine a little to automatically require all the components and format their names like:

./icons/Hamburger.tsx -> icons-hamburger like so:

document.addEventListener('turbolinks:load', () => {
  const context = require.context('components', true, /\.tsx$/)
  context.keys().forEach((key) => {
    const {default: Component} = require(`${key}`)
    const path = key
      .substr(2)
      .replace('/', '-')
      .replace('.tsx', '')
      .toLowerCase()
    registerComponent(Component, path)
  })
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment