Інваріантне порушення: _registerComponent (…): Цільовий контейнер не є елементом DOM


387

Я отримую цю помилку після створення тривіальної прикладу сторінки React:

Неприхована помилка: Інваріантне порушення: _registerComponent (...): Цільовий контейнер не є елементом DOM.

Ось мій код:

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

Що це означає?


8
@ go-oleg: Це коротке позначення ES6. Це не проблема, тому що у react-tools є ES6-транспілер. Дивіться тут
Дан Абрамов

14
Я зіткнувся з цією самою помилкою, і, як вважають інші, це тому, що ваш файл bundle.js завантажується занадто рано. Перемістіть тег <script> в тіло (як останній рядок перед закриттям тега </body>), щоб вирішити цю помилку.
Тодд Р

2
ось це не допомагає
daslicht

@daslicht Я сподіваюся, що ти знайшов свою відповідь, але просто так сказано: ДВОЙНА ПЕРЕВІРКА, що ти не змішуєш класи та ідентифікатори. document.getElementById ("foo") ніколи і ніколи не знайде тег, який читає <div class = "foo">
Дейв Кантер

Відповіді:


625

На момент виконання сценарію documentелемент ще недоступний, тому що scriptсам знаходиться в head. Незважаючи на те , що це правильне рішення , щоб тримати scriptв headі надавати на DOMContentLoadedподії , це навіть краще покласти ваші scriptна самому дні body і візуалізації кореневого компонента до divперед ним , як це:

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

і в bundle.jsдзвінку:

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

Ви завжди повинні надавати вкладені місця divзамість body. В іншому випадку всілякі сторонні коди (Google Font Loader, плагіни веб-переглядача тощо) можуть змінювати bodyвузол DOM, коли React цього не очікує, і викликати дивні помилки, які дуже важко відстежити та налагодити. Детальніше про це питання.

Приємно scriptв тому, що внизу є те, що воно не заблокує візуалізацію, поки не завантажиться сценарій, якщо ви додасте візуалізацію сервера React до свого проекту.


Оновлення: (07 жовтня 2015 р. | V0.14 )

React.renderзастаріло, ReactDOM.render замість цього використовуйте .

Приклад:

import ReactDOM from 'react-dom';

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

3
Я використовую заяви про імпорт у webpack і все ще отримую цю помилку. Я думав, що webpack подбає про порядок завантаження скриптів ні?
thetrystero

4
Розглянемо використання defer <script defer src = " fb.me/react-0.14.7.js" ></script> <script defer src =" fb.me/react-dom-0.14.7.js"></ script > <! - код вашого додатка зараз -> <script defer src = "app.js"> </script> </body>
приземлився

4
@thetrystero Ні, webpack не знає про відносне місце пакету вашої програми до вузлів DOM, на яких він працює.
Дан Абрамов

1
Така явна помилка - просто поміщення сценарію нижче корінця
діва

1
Це не випадок @DanAbramov, але я отримав ту саму помилку, використовуючи цільовий контейнер без повного тегу закриття (наприклад, <section id = "" />)
Кріс

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 +)

Примітка : Наявність <script async src="..."></script>у заголовку гарантує, що браузер почне завантажувати пакет JavaScript перед завантаженням вмісту HTML.

Джерело: React Starter Kit , навантажувач ізоморфного стилю


5
Це ReactDOM.renderзамість React.render.
Конрадо Фонсека

Попереджувальна примітка: якщо ви встановите свою реакцію на завантаження асинхронно, це створює перегонну умову - якщо браузер закінчить розбирати сторінку до виконання JS, ви все в порядку. Якщо JS буде завантажено до розбору сторінки, у вас з’явиться той самий випуск, про який йдеться. deferможе бути кращим варіантом
BRasmussen

16

готова функція може бути використана в такий спосіб:

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

Якщо ви не хочете використовувати jQuery, ви можете скористатися onloadфункцією:

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

6
Думаю, DOMContentLoadedбуло б доцільніше навіть обробляти, ніж load(саме для цього використовується jQuery ). Ви також можете це зробити в JS window.addEventListener, не потребуючи вбудованих обробників та глобальних функцій.
Дан Абрамов

3
Зауважте, що рендеркомпонент буде амортизований. Використовуйте натомість React.render ().
Томміксі

2
Я використовую react-rails, тому переміщення тега сценарію до нижньої частини тегу не було варіантом. $(document).readyвирішив проблему. О і так використовувати renderзамість renderComponent.
ltrainpr

1
Вкрай погана практика використовувати jQuery з React. Використовуйте будь-який, але не обидва одночасно.
агрегат1166877

11

просто дивна здогадка, як щодо додавання до index.html наступного:

type="javascript"

подобається це:

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

Для мене це спрацювало! :-)


3
Щойно FYI, це спричинило проблеми для мене, де type="text/javascript"працювали належним чином.
steezeburger

Це жахливо, що насправді виправлено мою проблему. якийсь сумний, але не впевнений, кого звинувачувати в цьому, реагувати чи нарікати?
Вільям Хоулі

6

Я зіткнувся з тією ж помилкою. Це виявилося причиною простого друку після зміни мого коду з:

document.getElementById('root')

до

document.querySelector('root')

Зауважте, що немає "#"

document.querySelector('#root')

Просто розміщуйте повідомлення, якщо це допоможе комусь іншому вирішити цю помилку.


4

Так, в основному те, що ви зробили правильно, за винятком того, що ви забуваєте, що JavaScript синхронізується в багатьох випадках, тому ви запускаєте код до завантаження DOM , існує кілька способів вирішити це:

1) Перевірте, чи повністю завантажений DOM , а потім робіть все, що завгодно, ви можете слухати DOMContentLoaded, наприклад:

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

2) Дуже поширеним способом є додавання тегу сценарію в нижній частині вашого document(після тегу body):

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

3) Використання window.onload, яке звільняється під час завантаження всієї сторінки (img тощо)

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

4) Використання document.onload, яке звільняється, коли DOM готовий:

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

Є ще більше варіантів, щоб перевірити, чи DOM готовий, але коротка відповідь НЕ запускайте жодного сценарію, перш ніж переконатися, що ваш DOM готовий у всіх випадках ...

JavaScript працює разом із елементами DOM, і якщо вони недоступні, повернеться до нуля , може порушити всю програму ... тому завжди переконайтеся, що ви повністю готові запустити JavaScript, перш ніж робити ...


2

Якщо ви використовуєте webpack для візуалізації вашої реакції та використовуєте HtmlWebpackPlugin у своїй реакції, цей плагін сам будує свій порожній index.html і вводить у нього файл js, тому він не містить елемент div, оскільки HtmlWebpackPlugin може створити власний індекс. html та дайте свою адресу цьому плагіну в моєму webpack.config.js

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

і це мій файл 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
Навіщо використовувати HtmlWebpackPluginтут плагін, якщо він використовується для посилання на статичний файл HTML?
Гаррі Чо

1

У моєму випадку ця помилка була викликана гарячим перезавантаженням під час введення нових класів. На цьому етапі проекту використовуйте звичайні спостерігачі для складання вашого коду.


1

Для тих, хто використовує ReactJS.Net та отримує цю помилку після публікації:

Перевірте властивості файлів .jsx і переконайтеся, що Build Actionвстановлено значення Content. Ті, які встановлені None, не публікуються. Я вирішив це рішення з цієї відповіді .


1

Я наткнувся на подібне / те саме повідомлення про помилку. У моєму випадку у мене не було цільового вузла DOM, який би мав визначити компонент ReactJS. Переконайтеся, що цільовий вузол HTML добре визначений із відповідним "id" або "name" разом з іншими атрибутами HTML (підходить для вашої потреби в дизайні)


У мене було подібне питання. Зважаючи на те, я мав оператор <code> if </code>, де очікуваний цільовий елемент повинен бути згенерований, якщо умова була виконана. У моєму випадку належний елемент не виводився через стан, але сценарій виконувався та намагався змонтувати компонент на елементі, який не існував у DOM.
Рафал Кіпсер

0

просто зробити базовий HTML CSS js та відтворити скрипт з 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

Коли ви отримали:

Помилка: Uncaught Error: Цільовий контейнер не є елементом DOM.

Ви можете використовувати подію DOMContentLoaded або перемістити <script ...></script>тег у нижній частині тіла.

У DOMContentLoaded подія спрацьовує , коли первісний HTML документ був повністю завантажений і розібраним, не чекаючи таблиці стилів, зображень і підрамників для завершення завантаження.

document.addEventListener("DOMContentLoaded", function(event) {
  ReactDOM.render(<App />, document.getElementById('root'));
})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.