Violation invariante: _registerComponent (…): le conteneur cible n'est pas un élément DOM

388

Je reçois cette erreur après une page d'exemple React triviale:

Erreur non interceptée: violation invariante: _registerComponent (...): le conteneur cible n'est pas un élément DOM.

Voici mon 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>

Qu'est-ce que ça veut dire?

Dan Abramov
la source
8
@ go-oleg: Il s'agit d'une notation courte ES6. Ce n'est pas le problème car react-tools a un transpilateur ES6. Voir ici
Dan Abramov
14
J'ai rencontré cette même erreur, et comme d'autres l'ont suggéré, c'est parce que votre fichier bundle.js se charge trop tôt. Déplacez votre balise <script> dans le corps (comme la dernière ligne avant la balise </body> de fermeture) pour résoudre cette erreur.
Todd R
2
ça n'aide pas ici
daslicht
@daslicht J'espère que vous avez trouvé votre réponse, mais il est juste dit: DOUBLE VÉRIFIEZ que vous ne mélangez pas les classes et les identifiants. document.getElementById ("foo") ne trouvera jamais, jamais, jamais une balise qui lit <div class = "foo">
Dave Kanter

Réponses:

626

Au moment où le script est exécuté, l' documentélément n'est pas encore disponible, car scriptlui-même est dans le head. Bien qu'il soit une solution valable pour maintenir scripten headet rendre le DOMContentLoadedcas , il est encore mieux de mettre votre scriptau fond même du body et rendre composant racine à un divavant comme ceci:

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

et dans le bundle.js, appelez:

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

Vous devez toujours effectuer un rendu sur un imbriqué divau lieu de body. Sinon, toutes sortes de codes tiers (Google Font Loader, plugins de navigateur, peu importe) peuvent modifier le bodynœud DOM lorsque React ne s'y attend pas et provoquer des erreurs étranges très difficiles à tracer et à déboguer. En savoir plus sur ce problème.

La bonne chose à mettre scripten bas est qu'il ne bloquera pas le rendu jusqu'à ce que le script se charge au cas où vous ajouteriez le rendu du serveur React à votre projet.


Mise à jour: (07 octobre 2015 | v0.14 )

React.renderest obsolète, utilisez ReactDOM.render plutôt.

Exemple:

import ReactDOM from 'react-dom';

ReactDOM.render(<App />, document.getElementById('root'));
Dan Abramov
la source
3
J'utilise des instructions d'importation dans webpack et j'obtiens toujours cette erreur. Je pensais que webpack se chargerait de l'ordre de chargement des scripts non?
thetrystero
4
Pensez à utiliser defer <script defer src = " fb.me/react-0.14.7.js " ></script> <script defer src =" fb.me/react-dom-0.14.7.js"></ script > <! - votre code d'application maintenant -> <script defer src = "app.js"> </script> </body>
atterri le
4
@thetrystero Non, webpack n'a aucune connaissance de l'emplacement relatif du bundle de votre application par rapport aux noeuds DOM sur lesquels il opère.
Dan Abramov
1
Une telle erreur cryptique - le simple fait de mettre le script en dessous de la racine div l'a fait fonctionner ...
kchoi
1
Ce n'est pas le cas de @DanAbramov mais j'ai reçu la même erreur en utilisant un conteneur cible sans balise de fermeture complète (par exemple <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 +)

Remarque : Le fait d'avoir <script async src="..."></script>dans l'en-tête garantit que le navigateur commencera à télécharger le bundle JavaScript avant chargement du contenu HTML.

Source: React Starter Kit , chargeur de style isomorphe

Konstantin Tarkus
la source
5
C'est ReactDOM.renderau lieu de React.render.
Conrado Fonseca
Remarque d'avertissement: si vous définissez votre réaction pour se charger de manière asynchrone, cela crée une condition de concurrence - si le navigateur termine l'analyse de la page avant l'exécution du JS, tout va bien. Si le JS est chargé avant l'analyse de la page, vous vous retrouverez avec le même problème que la question. deferpeut être une meilleure option
BRasmussen
16

la fonction prête peut être utilisée comme ceci:

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

Si vous ne souhaitez pas utiliser jQuery, vous pouvez utiliser la onloadfonction:

<body onload="initReact()">...</body>
nils petersohn
la source
6
Je pense qu'il DOMContentLoadedserait même plus approprié de gérer que load(c'est ce que jQuery utilise ). Vous pouvez également le faire dans JS avec window.addEventListener, pas besoin de gestionnaires en ligne et de fonctions globales.
Dan Abramov
3
Notez que renderComponent sera amorti. Utilisez plutôt React.render ().
Tommyixi
2
J'utilise react-rails, donc déplacer la balise de script au bas de la balise body n'était pas une option. $(document).readyrésolu le problème. Oh et oui, utilisez renderau lieu de renderComponent.
ltrainpr
1
Il est extrêmement mauvais d'utiliser jQuery avec React. Utilisez les deux, mais pas les deux en même temps.
aggregate1166877
11

juste une supposition sauvage, que diriez-vous d'ajouter à index.html ce qui suit:

type="javascript"

comme ça:

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

Pour moi, ça a marché! :-)

taquiles
la source
3
Juste pour info, cela m'a causé des problèmes où cela type="text/javascript"fonctionnait correctement.
steezeburger
C'est terrible qui est en fait résolu mon problème. un peu triste, mais vous ne savez pas à qui blâmer celui-ci, réagir ou babiller?
William Howley
6

J'ai rencontré la même erreur. Il s'est avéré être causé par une simple faute de frappe après avoir changé mon code de:

document.getElementById('root')

à

document.querySelector('root')

Remarquez le «#» manquant. Il aurait dû être

document.querySelector('#root')

Il suffit de poster au cas où cela aiderait quelqu'un d'autre à résoudre cette erreur.

mangakid
la source
4

Oui, ce que vous avez fait est juste, sauf que vous oubliez que JavaScript est synchronisé dans de nombreux cas, donc vous exécutez le code avant votre DOM soit chargé, il y a quelques façons de résoudre ce problème:

1) Vérifiez si DOM est complètement chargé, puis faites ce que vous voulez, vous pouvez écouter DOMContentLoaded par exemple:

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

2) La manière la plus courante consiste à ajouter la balise de script au bas de votre document(après la balise body):

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

3) Utilisation de window.onload, qui se déclenche lorsque la page entière est chargée (img, etc.)

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

4) Utilisation de document.onload, qui se déclenche lorsque le DOM est prêt:

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

Il y a encore plus d'options pour vérifier si DOM est prêt, mais la réponse courte est de NE PAS exécuter de script avant de vous assurer que votre DOM est prêt dans tous les cas ...

JavaScript fonctionne avec les éléments DOM et s'ils ne sont pas disponibles, retournera null , pourrait casser toute l'application ... alors assurez-vous toujours que vous êtes entièrement prêt à exécuter votre JavaScript avant de le faire ...

Alireza
la source
2

Si vous utilisez webpack pour rendre votre réaction et utilisez HtmlWebpackPlugin dans votre react, ce plugin construit son index.html vierge par lui-même et y injecte le fichier js, donc il ne contient pas d'élément div, comme les documents HtmlWebpackPlugin vous pouvez construire votre propre index. html et donnez son adresse à ce plugin, dans mon webpack.config.js

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

et voici mon fichier index.html

<!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
la source
1
Pourquoi utiliser le HtmlWebpackPluginplugin ici s'il est utilisé pour référencer un fichier HTML statique?
Harry Cho
1

Dans mon cas, cette erreur a été causée par un rechargement à chaud, lors de l'introduction de nouvelles classes. À cette étape du projet, utilisez des observateurs normaux pour compiler votre code.

Micros
la source
1

Pour ceux qui utilisent ReactJS.Net et obtiennent cette erreur après une publication:

Vérifiez les propriétés de vos fichiers .jsx et assurez-vous qu'il Build Actionest défini sur Content. Ceux définis pour Nonene seront pas publiés. Je suis tombé sur cette solution de cette réponse SO .

Jecoms
la source
1

J'ai rencontré un message d'erreur similaire / même. Dans mon cas, je n'avais pas le noeud DOM cible qui doit rendre le composant ReactJS défini. Assurez-vous que le nœud cible HTML est bien défini avec "id" ou "nom" approprié, ainsi que d'autres attributs HTML (adaptés à vos besoins de conception)

anie codeskol
la source
J'ai eu un problème similaire. En vue, j'avais une instruction <code> if </code> où l'élément cible attendu devait être généré si la condition était remplie. Dans mon cas, l'élément approprié n'a pas été rendu à cause de la condition, mais le script a été exécuté et a essayé de monter le composant sur l'élément qui n'existait pas dans DOM.
Rafal Cypcer
0

il est facile de créer des js HTML CSS de base et de rendre le script à partir de js

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
la source
0

Quand tu as:

Erreur: erreur non interceptée: le conteneur cible n'est pas un élément DOM.

Vous pouvez utiliser l' événement DOMContentLoaded ou déplacer votre <script ...></script>balise au bas de votre corps.

L' événement DOMContentLoaded se déclenche lorsque le document HTML initial a été entièrement chargé et analysé, sans attendre la fin du chargement des feuilles de style, des images et des sous-trames.

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