Programmers learn & share
0 votes
105 views

Problem :

I often face below error after making the trivial React example page:

“Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.”

Below is my code:

/** The @jsx React.DOM */
'use strict';
var MyReact = require('react');
var MyApp = MyReact.createClass({
  render() {
    return <h1>Yo</h1>;
  }
});
MyReact.renderComponent(<App />, document.body);

 

Below is my HTML:

<html>
<head>
  <script src="/mybundle.js"></script>
</head>
<body>
</body>
</html>

What does the above error mean?

by (7.5k points)   | 105 views

2 Answers

0 votes

Solution :

By the time your script is executed, the document element is not available yet, as script itself is in your head. While it is the valid solution to keep the script in your head and render on the DOMContentLoaded event, it is even better to put the script at a very bottom of a body and render root component to the div before it like below:

<html>

<head>

</head>

<body>

  <div id="root"></div>

  <script src="/mybundle.js"></script>

</body>

</html>

 

and in your mybundle.js, please call:

MyReact.render(<App />, document.getElementById('root'));

You must always render to the nested div instead of the body. Otherwise, all the sorts of third-party code can modify your body DOM node when the React doesn't expect it, and cause the weird errors that are extreamly hard to trace and debug. 

The React.render is deprecated, use the ReactDOM.render instead.

Example:

import ReactDOM from 'react-dom';

ReactDOM.render(<App />, document.getElementById('root'));

by (36.1k points)  
0 votes

Solution:

By the time script is executed, document element is not available yet, because script itself is in the head. While it's a valid solution to keep script in head and render on DOMContentLoaded event, it's even better to put your script at the very bottom of the body and render root component to a div before it like this:

Code:

<html>
<head>
</head>
<body>
  <div id="root"></div>
  <script src="/bundle.js"></script>
</body>
</html>

and in the 

bundle.js

Call

React.render(<App />, document.getElementById('root'));

You should always render to a nested div instead of body. Otherwise, all sorts of third-party code (Google Font Loader, browser plugins, whatever) can modify the body DOM node when React doesn't expect it, and cause weird errors that are very hard to trace and debug.

The nice thing about putting script at the bottom is that it won't block rendering until script load in case you add React server rendering to your project.

More Specifically /imdex.html

<!doctype html>
<html>
  <head>
    <title>My Application</title>
    <!-- load application bundle asynchronously -->
    <script async src="/app.js"></script>
    <style type="text/css">
      /* pre-rendered critical path CSS (see isomorphic-style-loader) */
    </style>
  </head>
  <body>
    <div id="app">
      <!-- pre-rendered markup of your JavaScript app (see isomorphic apps) -->
    </div>
  </body>
</html>

 

/app.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

function run() {
  ReactDOM.render(<App />, document.getElementById('app'));
}

const loadedStates = ['complete', 'loaded', 'interactive'];

if (loadedStates.includes(document.readyState) && document.body) {
  run();
} else {
  window.addEventListener('DOMContentLoaded', run, false);
}

 

N.B: Having 

<script async src="..."></script> 

in the header ensures that the browser will start downloading JavaScript bundle before HTML content is loaded

by (10k points)  
2,221 questions
2,698 answers
59 comments
241 users