Niezmienne naruszenie: _registerComponent (…): Kontener docelowy nie jest elementem DOM


387

Ten błąd pojawia się po utworzeniu trywialnej przykładowej strony React:

Nieprzechwycony błąd: Niezmienne naruszenie: _registerComponent (...): Kontener docelowy nie jest elementem DOM.

Oto mój kod:

/** @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>

Co to znaczy?


8
@ go-oleg: To jest krótka notacja ES6. To nie jest problem, ponieważ reagujące narzędzia mają transpilator ES6. Zobacz tutaj
Dan Abramov,

14
Zetknąłem się z tym samym błędem i, jak sugerują inni, to dlatego, że plik bundle.js ładuje się zbyt wcześnie. Przenieś swój tag <script> do treści (jako ostatni wiersz przed zamykającym tagiem </body>), aby rozwiązać ten błąd.
Todd R

2
to nie pomaga tutaj
daslicht,

@daslicht Mam nadzieję, że znalazłeś swoją odpowiedź, ale powiedziano tak: PODWÓJNIE SPRAWDŹ, czy nie mieszasz klas z identyfikatorami. document.getElementById („foo”) nigdy, nigdy, nigdy nie znajdzie znacznika o treści <div class = „foo”>
Dave Kanter

Odpowiedzi:


625

Do czasu wykonania skryptu documentelement nie jest jeszcze dostępny, ponieważ scriptsam jest w pliku head. O ile jest to ważne rozwiązanie, aby utrzymać scriptsię headi render na DOMContentLoadedimprezy , to nawet lepiej, aby umieścić swoje scriptu samego dołu body i renderowanie składnik głównego do divprzed nim tak:

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

oraz w bundle.js:

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

Zawsze powinieneś renderować do zagnieżdżonego div zamiast body. W przeciwnym razie wszelkiego rodzaju kody innych firm (moduł ładujący czcionki Google, wtyczki przeglądarki itp.) Mogą modyfikować bodywęzeł DOM, gdy React nie oczekuje go, i powodować dziwne błędy, które są bardzo trudne do śledzenia i debugowania. Przeczytaj więcej o tym problemie.

Zaletą umieszczania scriptna dole jest to, że nie blokuje renderowania do momentu załadowania skryptu w przypadku dodania renderowania serwera React do projektu.


Aktualizacja: (07 października 2015 r. | v0.14 )

React.renderjest przestarzałe, użyj ReactDOM.render zamiast niego.

Przykład:

import ReactDOM from 'react-dom';

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

3
Korzystam z instrukcji importu w pakiecie internetowym i nadal otrzymuję ten błąd. Myślałem, że webpack zajmie się kolejnością ładowania skryptów nie?
thetrystero

4
Rozważ użycie defer <script defer src = " fb.me/react-0.14.7.js " ></script> <script defer src =" fb.me/react-dom-0.14.7.js"></ skrypt > <! - teraz twój kod aplikacji -> <script defer src = "app.js"> </script> </body>
wylądował

4
@thetrystero Nie, webpack nie ma wiedzy o względnym miejscu pakietu aplikacji do węzłów DOM, na których działa.
Dan Abramov,

1
Taki tajemniczy błąd - po prostu umieszczenie skryptu poniżej roota div sprawiło, że zadziałało ...
kchoi

1
To nie jest przypadek @DanAbramov, ale otrzymałem ten sam błąd, używając kontenera docelowego bez pełnego tagu zamykającego (na przykład <id sekcji = "" />)
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 +)

Uwaga : Posiadanie <script async src="..."></script>nagłówka gwarantuje, że przeglądarka rozpocznie pobieranie pakietu JavaScript wcześniej załadowaniem treści HTML.

Źródło: React Starter Kit , moduł ładujący w stylu izomorficznym


5
Jest ReactDOM.renderzamiast React.render.
Conrado Fonseca

Uwaga: jeśli ustawisz reakcję na asynchroniczne ładowanie, stworzy to warunek wyścigu - jeśli przeglądarka zakończy parsowanie strony przed wykonaniem JS, wszystko w porządku. Jeśli JS zostanie załadowany przed parsowaniem strony, skończysz z tym samym problemem, o którym chodzi. defermoże być lepszym rozwiązaniem
BRasmussen

16

funkcja gotowy może być stosowany tak:

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

Jeśli nie chcesz używać jQuery, możesz użyć onloadfunkcji:

<body onload="initReact()">...</body>

6
Myślę, że DOMContentLoadedbyłoby bardziej odpowiednie nawet do obsługi niż load(tego używa jQuery ). Możesz to również zrobić w JS window.addEventListener, bez potrzeby korzystania z wbudowanych procedur obsługi i funkcji globalnych.
Dan Abramov

3
Uwaga, renderComponent będzie amortyzowany. Zamiast tego użyj React.render ().
Tommyixi,

2
Używam szyn reagujących, więc przeniesienie znacznika skryptu na spód znacznika body nie było opcją. $(document).readyRozwiązać problem. No i tak, użyj renderzamiast renderComponent.
ltrainpr

1
Używanie jQuery z React jest bardzo złą praktyką. Użyj jednego, ale nie obu jednocześnie.
aggregate1166877

11

zwykłe zgadywanie, co powiesz na dodanie do index.html:

type="javascript"

lubię to:

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

Dla mnie to zadziałało! :-)


3
Tylko do twojej wiadomości, to spowodowało problemy, dla których type="text/javascript"działało poprawnie.
steezeburger

To okropne, że naprawiłem mój problem. trochę smutne, ale nie wiesz, kogo winić za to, zareagować czy babel?
William Howley,

6

Wystąpił ten sam błąd. Okazało się, że jest to spowodowane zwykłą literówką po zmianie mojego kodu z:

document.getElementById('root')

do

document.querySelector('root')

Zauważ brakujące „#” Powinno być

document.querySelector('#root')

Tylko publikowanie na wypadek, gdyby pomogło to komuś rozwiązać ten błąd.


4

Tak, w zasadzie to, co zrobiłeś, jest słuszne, ale zapominasz, że JavaScript jest synchronizowany w wielu przypadkach, więc jeśli uruchamiasz kod przed załadowaniem DOM , istnieje kilka sposobów na rozwiązanie tego:

1) Sprawdź, czy DOM jest w pełni załadowany, a następnie rób, co chcesz, możesz odsłuchać DOMContentLoaded, na przykład:

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

2) Bardzo popularnym sposobem jest dodanie znacznika skryptu do dolnej części document(po znaczniku body):

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

3) Używanie window.onload, które jest uruchamiane po załadowaniu całej strony (img itp.)

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

4) Używanie document.onload, które jest uruchamiane, gdy DOM jest gotowy:

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

Jest jeszcze więcej opcji, aby sprawdzić, czy DOM jest gotowy, ale krótka odpowiedź brzmi: NIE uruchamiaj żadnego skryptu, zanim nie upewnisz się, że DOM jest gotowy w każdym przypadku ...

JavaScript działa razem z elementami DOM i jeśli nie są one dostępne, zwróci null , może uszkodzić całą aplikację ... więc zawsze upewnij się, że jesteś w pełni gotowy do uruchomienia JavaScript zanim to zrobisz ...


2

Jeśli używasz webpacka do renderowania twojego reagowania i używasz HtmlWebpackPlugin w swojej reakcji, ta wtyczka sama zbuduje swój pusty index.html i wstrzykuje do niego plik js, więc nie zawiera elementu div, ponieważ HtmlWebpackPlugin docs możesz zbudować własny indeks. HTML i podaj adres tej wtyczki w moim pliku webpack.config.js

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

i to jest mój plik 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>

1
Po co używać HtmlWebpackPluginwtyczki tutaj, jeśli jest używana do odwoływania się do statycznego pliku HTML?
Harry Cho,

1

W moim przypadku ten błąd został spowodowany przez ponowne ładowanie na gorąco podczas wprowadzania nowych klas. Na tym etapie projektu skompiluj kod za pomocą zwykłych obserwatorów.


1

Dla osób używających ReactJS.Net i otrzymujących ten błąd po opublikowaniu:

Sprawdź właściwości plików .jsx i upewnij się, że Build Actionjest ustawiony na Content. Te ustawione na Nonenie zostaną opublikowane. Natrafiłem na to rozwiązanie z tej SO odpowiedzi .


1

Natrafiłem na podobny / taki sam komunikat o błędzie. W moim przypadku nie miałem docelowego węzła DOM, który ma renderować zdefiniowany komponent ReactJS. Upewnij się, że docelowy węzeł HTML jest dobrze zdefiniowany za pomocą odpowiedniego „id” lub „name”, a także innych atrybutów HTML (odpowiednich do potrzeb projektu)


Miałem podobny problem. W widoku miałem instrukcję <code> if </code>, gdzie oczekiwany element docelowy powinien zostać wygenerowany, jeśli warunek zostanie spełniony. W moim przypadku właściwy element nie był renderowany z powodu warunku, ale skrypt wykonał i próbował zamontować komponent na elemencie, który nie istniał w DOM.
Rafal Cypcer

0

to proste, po prostu utwórz podstawowy plik CSS js HTML i wyrenderuj skrypt z pliku 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>


0

Kiedy dostaniesz:

Błąd: Nieprzechwycony błąd: Kontener docelowy nie jest elementem DOM.

Możesz użyć zdarzenia DOMContentLoaded lub przenieść <script ...></script>tag w dolnej części ciała.

W DOMContentLoaded Zdarzenie gdy początkowy dokument HTML został całkowicie załadowane i analizowane, bez czekania na arkusze stylów, obrazów i ram pomocniczych, aby zakończyć ładowanie.

document.addEventListener("DOMContentLoaded", function(event) {
  ReactDOM.render(<App />, document.getElementById('root'));
})
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.