// Unobtrusive scripting adapter for React
(function(document, window, React) {
  var CLASS_NAME_ATTR = 'data-react-class';
  var PROPS_ATTR = 'data-react-props';

  // jQuery is optional. Use it to support legacy browsers.
  var $ = (typeof jQuery !== 'undefined') && jQuery;

  var findReactDOMNodes = function() {
    var SELECTOR = '[' + CLASS_NAME_ATTR + ']';
    if ($) {
      return $(SELECTOR);
    } else {
      return document.querySelectorAll(SELECTOR);
    }
  };

  var mountReactComponents = function() {
    var nodes = findReactDOMNodes();
    for (var i = 0; i < nodes.length; ++i) {
      var node = nodes[i];
      var className = node.getAttribute(CLASS_NAME_ATTR);
      // Assume className is simple and can be found at top-level (window).
      // Fallback to eval to handle cases like 'My.React.ComponentName'.
      var constructor = window[className] || eval.call(window, className);
      var propsJson = node.getAttribute(PROPS_ATTR);
      var props = propsJson && JSON.parse(propsJson);
      React.renderComponent(constructor(props), node);
    }
  };

  var unmountReactComponents = function() {
    var nodes = findReactDOMNodes();
    for (var i = 0; i < nodes.length; ++i) {
      React.unmountComponentAtNode(nodes[i]);
    }
  };

  // Register page load & unload events
  if ($) {
    $(mountReactComponents);
    $(window).unload(unmountReactComponents);
  } else {
    document.addEventListener('DOMContentLoaded', mountReactComponents);
    window.addEventListener('unload', unmountReactComponents);
  }

  // Turbolinks specified events
  if (typeof Turbolinks !== 'undefined') {
    var handleEvent;
    if ($) {
      handleEvent = function(eventName, callback) {
        $(document).on(eventName, callback);
      }
    } else {
      handleEvent = function(eventName, callback) {
        document.addEventListener(eventName, callback);
      }
    }
    handleEvent('page:change', mountReactComponents);
    handleEvent('page:before-change', unmountReactComponents);
  }
})(document, window, React);

@@ -271,16 +271,153 @@
 Query;%0A%0A
+  // Maps DOM nodes to booleans specifying whether or not those%0A  // nodes already have a component mounted in them%0A  var mounted = %7B%7D;%0A%0A
   var fi
@@ -1149,16 +1149,47 @@
 sJson);%0A
+%0A      if (!mounted%5Bnode%5D) %7B%0A  
       Re
@@ -1231,24 +1231,62 @@
 ps), node);%0A
+        mounted%5Bnode%5D = true;%0A      %7D%0A
     %7D%0A  %7D;%0A%0A
@@ -1457,16 +1457,44 @@
 es%5Bi%5D);%0A
+      delete mounted%5Bnode%5D;%0A
     %7D%0A  

Make sure to only mount components once per DOM node