Skip to content

Instantly share code, notes, and snippets.

@jwo
Last active April 19, 2020 21:31
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwo/7d9524d9075d129491d810cdf40f34b2 to your computer and use it in GitHub Desktop.
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
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

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

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)
})

@jesster2k10
Copy link

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