Invariante Verletzung: _registerComponent (…): Der Zielcontainer ist kein DOM-Element

388

Ich erhalte diesen Fehler nach einer trivialen React-Beispielseite:

Nicht erfasster Fehler: Invariante Verletzung: _registerComponent (...): Der Zielcontainer ist kein DOM-Element.

Hier ist mein Code:

/** @jsx React.DOM */
'use strict';

var React = require('react');

var App = React.createClass({
  render() {
    return <h1>Yo</h1>;
  }
});

React.renderComponent(<App />, document.body);

HTML:

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

Was bedeutet das?

Dan Abramov
quelle
8
@ go-oleg: Dies ist die ES6-Kurznotation. Dies ist nicht das Problem, da React-Tools über einen ES6-Transpiler verfügt. Siehe hier
Dan Abramov
14
Ich bin auf denselben Fehler gestoßen, und wie andere vorgeschlagen haben, liegt es daran, dass Ihre Datei bundle.js zu früh geladen wird. Verschieben Sie Ihr <script> -Tag in den Body (als letzte Zeile vor dem schließenden </ body> -Tag), um diesen Fehler zu beheben.
Todd R
2
das hilft hier nicht
daslicht
@daslicht Ich hoffe, Sie haben Ihre Antwort gefunden, aber nur so heißt es: DOPPELTE PRÜFUNG, dass Sie keine Klassen und IDs verwechseln. document.getElementById ("foo") wird niemals ein Tag finden, das <div class = "foo"> lautet
Dave Kanter

Antworten:

626

Zum Zeitpunkt der Ausführung des Skripts ist das documentElement noch nicht verfügbar, da es scriptsich in der befindet head. Zwar ist es eine gültige Lösung ist zu halten , scriptin headund auf machen DOMContentLoadedVeranstaltung , ist es noch besser zu Ihrem setzen scriptam unteren Ende der body und Wurzelkomponente zu einem machen , divbevor es wie folgt aus :

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

und in der bundle.js, rufen Sie an:

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

Sie sollten immer in eine verschachtelte divstatt rendern body. Andernfalls können alle Arten von Code von Drittanbietern (Google Font Loader, Browser-Plugins usw.) den bodyDOM-Knoten ändern , wenn React dies nicht erwartet, und seltsame Fehler verursachen, die sehr schwer zu verfolgen und zu debuggen sind. Lesen Sie mehr über dieses Problem.

Das Schöne scriptam unteren Rand ist, dass das Rendern erst nach dem Laden des Skripts blockiert wird, falls Sie Ihrem Projekt das Rendern von React-Servern hinzufügen.


Update: (07. Oktober 2015 | v0.14 )

React.renderist veraltet, verwenden Sie ReactDOM.render stattdessen.

Beispiel:

import ReactDOM from 'react-dom';

ReactDOM.render(<App />, document.getElementById('root'));
Dan Abramov
quelle
3
Ich verwende Importanweisungen in Webpack und erhalte immer noch diesen Fehler. Ich dachte, Webpack kümmert sich um die Reihenfolge des Ladens von Skripten, nein?
Thetrystero
4
Erwägen Sie die Verwendung von defer <script defer src = " fb.me/react-0.14.7.js " > </ script> <script defer src =" fb.me/react-dom-0.14.7.js " > < / script > <! - Ihr App-Code jetzt -> <script defer src = "app.js"> </ script> </ body>
landete
4
@thetrystero Nein, Webpack hat keine Kenntnis über die relative Position des Bundles Ihrer Anwendung zu den DOM-Knoten, auf denen es ausgeführt wird.
Dan Abramov
1
Solch ein kryptischer Fehler - nur das Skript unter root div zu setzen, hat es funktioniert ...
kchoi
1
Es ist nicht der Fall von @DanAbramov, aber ich habe den gleichen Fehler erhalten, indem ich einen Zielcontainer ohne vollständiges schließendes Tag verwendet habe (zum Beispiel <section id = "" />)
Chris
53

/index.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);
}

(IE9 +)

Hinweis : Wenn Sie <script async src="..."></script>den Header verwenden, wird sichergestellt, dass der Browser das JavaScript-Bundle herunterlädt, bevor HTML-Inhalte geladen werden.

Quelle: React Starter Kit , isomorpher Lader

Konstantin Tarkus
quelle
5
Es ist ReactDOM.renderstatt React.render.
Conrado Fonseca
Warnhinweis: Wenn Sie Ihre Reaktion so einstellen, dass sie asynchron geladen wird, wird eine Race-Bedingung erstellt. Wenn der Browser das Parsen der Seite vor der Ausführung des JS beendet, ist alles in Ordnung. Wenn der JS geladen wird, bevor die Seite analysiert wird, tritt das gleiche Problem auf, um das es bei der Frage geht. deferkann eine bessere Option sein
BRasmussen
16

Die Ready-Funktion kann folgendermaßen verwendet werden:

$(document).ready(function () {
  React.render(<App />, document.body);
});

Wenn Sie jQuery nicht verwenden möchten, können Sie die folgende onloadFunktion verwenden:

<body onload="initReact()">...</body>
nils petersohn
quelle
6
Ich denke, DOMContentLoadedwäre sogar angemessener zu handhaben als load(dies ist, was jQuery verwendet ). Sie können dies auch in JS window.addEventListenerohne Inline-Handler und globale Funktionen tun .
Dan Abramov
3
Beachten Sie, dass renderComponent abgeschrieben wird. Verwenden Sie stattdessen React.render ().
Tommyixi
2
Ich verwende React-Rails, sodass das Verschieben des Skript-Tags an den unteren Rand des Body-Tags keine Option war. $(document).readyProblem gelöst. Oh und ja renderstatt verwenden renderComponent.
ltrainpr
1
Es ist äußerst schlecht, jQuery mit React zu verwenden. Verwenden Sie beide, aber nicht beide gleichzeitig.
aggregate1166877
11

Nur eine wilde Vermutung, wie wäre es, wenn Sie Folgendes zu index.html hinzufügen:

type="javascript"

so was:

<script type="javascript" src="public/bundle.js"> </script>

Bei mir hat es geklappt! :-)

Taquiles
quelle
3
Nur zu Ihrer Information, dies verursachte Probleme für mich, wo es type="text/javascript"richtig funktionierte.
Steezeburger
Das ist schrecklich, dass mein Problem tatsächlich behoben ist. irgendwie traurig, aber nicht sicher, wem man die Schuld geben soll, reagieren oder babel?
William Howley
6

Ich bin auf den gleichen Fehler gestoßen. Es stellte sich heraus, dass dies durch einen einfachen Tippfehler verursacht wurde, nachdem ich meinen Code geändert hatte von:

document.getElementById('root')

zu

document.querySelector('root')

Beachten Sie das fehlende '#'. Es hätte sein sollen

document.querySelector('#root')

Nur posten, falls es jemand anderem hilft, diesen Fehler zu beheben.

Mangakid
quelle
4

Ja, im Grunde ist das , was Sie getan haben, richtig, außer dass Sie vergessen, dass JavaScript in vielen Fällen synchronisiert ist. Wenn Sie also den Code ausführen, bevor Ihr DOM geladen wird, gibt es nur wenige Möglichkeiten, dies zu lösen:

1) Überprüfen Sie, ob DOM vollständig geladen ist, und machen Sie dann, was Sie wollen. Sie können DOMContentLoaded zum Beispiel anhören :

<script>
  document.addEventListener("DOMContentLoaded", function(event) {
    console.log("DOM fully loaded and parsed");
  });
</script>

2) Sehr häufig wird das Skript-Tag am unteren Rand Ihres document(nach dem Body-Tag) hinzugefügt :

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

3) Using window.onload, das ausgelöst wird, wenn die gesamte Seite geladen wird (img usw.)

window.addEventListener("load", function() {
  console.log("Everything is loaded");
});

4) Verwenden document.onload, das ausgelöst wird, wenn das DOM bereit ist:

document.addEventListener("load", function() {
  console.log("DOM is ready");
});

Es gibt noch mehr Optionen, um zu überprüfen, ob DOM bereit ist, aber die kurze Antwort lautet: Führen Sie KEIN Skript aus, bevor Sie sichergestellt haben, dass Ihr DOM in jedem Fall bereit ist ...

JavaScript arbeitet mit DOM- Elementen zusammen. Wenn diese nicht verfügbar sind, wird null zurückgegeben , die gesamte Anwendung kann beschädigt werden. Stellen Sie daher immer sicher, dass Sie bereit sind, Ihr JavaScript auszuführen, bevor Sie dies tun.

Alireza
quelle
2

Wenn Sie Webpack zum Rendern Ihrer Reaktion verwenden und HtmlWebpackPlugin in Ihrer Reaktion verwenden, erstellt dieses Plugin seine leere index.html selbst und fügt eine js-Datei ein, sodass es kein div-Element enthält, da Sie als HtmlWebpackPlugin-Dokumente Ihren eigenen Index erstellen können. HTML und geben Sie seine Adresse an dieses Plugin in meiner webpack.config.js

plugins: [            
    new HtmlWebpackPlugin({
        title: 'dev',
        template: 'dist/index.html'
    })
],

und das ist meine index.html Datei

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="shortcut icon" href="">
    <meta name="viewport" content="width=device-width">
    <title>Epos report</title>
</head>
<body>
   <div id="app"></div>
   <script src="./bundle.js"></script>
</body>
</html>
ghazaleh javaheri
quelle
1
Warum hier das HtmlWebpackPluginPlugin verwenden, wenn es zum Verweisen auf statische HTML-Dateien verwendet wird?
Harry Cho
1

In meinem Fall wurde dieser Fehler durch Hot-Reload beim Einführen neuer Klassen verursacht. Verwenden Sie in dieser Phase des Projekts normale Beobachter, um Ihren Code zu kompilieren.

Micros
quelle
1

Für diejenigen, die ReactJS.Net verwenden und diesen Fehler nach einer Veröffentlichung erhalten:

Überprüfen Sie die Eigenschaften Ihrer .jsx-Dateien und stellen Sie sicher, dass auf eingestellt Build Actionist Content. Die festgelegten Werte Nonewerden nicht veröffentlicht. Ich bin auf diese Lösung aus dieser SO-Antwort gestoßen .

Jecoms
quelle
1

Ich bin auf eine ähnliche / gleiche Fehlermeldung gestoßen. In meinem Fall hatte ich nicht den Ziel-DOM-Knoten, der die ReactJS-Komponente definieren soll. Stellen Sie sicher, dass der HTML-Zielknoten mit der entsprechenden "ID" oder dem "Namen" sowie anderen HTML-Attributen (für Ihre Entwurfsanforderungen geeignet) gut definiert ist.

anie Codeskol
quelle
Ich hatte ein ähnliches Problem. In der Ansicht hatte ich die Anweisung <code> if </ code>, in der das erwartete Zielelement generiert werden sollte, wenn die Bedingung erfüllt war. In meinem Fall wurde das richtige Element aufgrund der Bedingung nicht gerendert, aber das Skript wurde ausgeführt und versuchte, eine Komponente auf ein Element zu hängen, das in DOM nicht vorhanden war.
Rafal Cypcer
0

Es ist einfach, einfache HTML-CSS-JS zu erstellen und das Skript aus JS zu rendern

mport React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

var destination = document.querySelector('#container');

   ReactDOM.render(
<div>
<p> hello world</p>
</div>, destination


	); 
body{

    text-align: center;
    background-color: aqua;
  padding: 50px;
  border-color: aqua;
  font-family: sans-serif;
}
#container{
  display: flex;
  justify-content: flex;

}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
   
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />   
    <title> app  </title>
  </head>
  <body>
 

    <div id="container">
      
    </div>

  </body>
</html>

Omar bakhsh
quelle
0

Wenn du hast:

Fehler: Nicht erfasst Fehler: Der Zielcontainer ist kein DOM-Element.

Sie können das DOMContentLoaded- Ereignis verwenden oder Ihr <script ...></script>Tag in den unteren Bereich Ihres Körpers verschieben.

Das DOMContentLoaded- Ereignis wird ausgelöst , wenn das ursprüngliche HTML-Dokument vollständig geladen und analysiert wurde, ohne darauf zu warten, dass Stylesheets, Bilder und Subframes vollständig geladen werden.

document.addEventListener("DOMContentLoaded", function(event) {
  ReactDOM.render(<App />, document.getElementById('root'));
})
A-312
quelle