Thanks for the live demo. I've determined that this is a problematic interaction between React 0.8 and Rails's Turbolinks. Here's a summary of what's happening:
On initial page load, the JavaScript file is evaluated, which loads jQuery, jquery-ujs, Turbolinks, React, and your app code. The initial render code is run, which renders the
Root
component into#content
. Because React relies on event delegation for performance, it attaches its event handlers here to the document.When you click on the "Fan" button,
render_fan
is called which pushes a history entry for/fan
and renders theFanRoot
component, replacing the existing children of#content
.When you click the back button, your browser sets the URL back to
/
and triggers apopstate
event, which Turbolinks catches. Turbolinks restores the original content of the<body>
tag, which causes the linked script to be reevaluated, because your JS is loaded in the body of the page instead of the head.This causes all of your JS to be rerun, causing a second, separate copy of React to be initialized (and causing your app code to be run again, which is how the Root component gets rerendered). This second copy of React would attach its own event listeners to the document, but React 0.8 has a bug where a second copy of React won't add its own event listeners, so only the first copy of React receives click events but it doesn't know about the onClick handler stored by the second React, so nothing happens.
Newer versions of React don't have this problem -- they're able to keep separate versions encapsulated, so each React instance will keep its own event handlers properly. I tested your app with React 0.10.0 and it works correctly.
However, I believe your use of Turbolinks here is incorrect and may cause you problems in the future. It sounds like to use Turbolinks properly, you should put script elements in your page <head>
, but since it looks like you're building a single-page app in React alone, you probably want to disable Turbolinks completely and just bind to popstate
yourself in order to re-render when the back button is clicked.