Нарушение инварианта: _registerComponent (…): целевой контейнер не является элементом DOM


388

Я получаю эту ошибку после создания тривиального примера страницы React:

Uncaught Ошибка: Инвариантное нарушение: _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. Это не проблема, потому что у реакционных инструментов есть транспортер ES6. Смотрите здесь
Дан Абрамов

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

2
вот это не поможет
daslicht

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

Ответы:


626

К моменту выполнения скрипта 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 позаботится о порядке загрузки скриптов нет?
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 Нет, веб-пакет не знает об относительном месте связки вашего приложения с узлами DOM, на которых оно работает.
Дан Абрамов

1
Такая загадочная ошибка - просто поместив скрипт ниже root div, он заработал ...
kchoi

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
Обратите внимание, что renderComponent будет амортизироваться. Вместо этого используйте React.render ().
Томмиикси

2
Я использую реагирующие направляющие, поэтому перемещение тега script в конец тега body было невозможным. $(document).readyрешил проблему. Ох и да, используйте renderвместо renderComponent.
ltrainpr

1
Использовать jQuery с React крайне плохо. Используйте либо, но не оба одновременно.
aggregate1166877

11

просто дикая догадка, как насчет добавления в index.html следующее:

type="javascript"

нравится:

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

Для меня это сработало! :-)


3
Просто к вашему сведению, это вызвало проблемы для меня, где, как 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) Очень распространенным способом является добавление тега script внизу вашего 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 и, если они недоступны, вернет значение null , может привести к поломке всего приложения ... поэтому всегда убедитесь, что вы полностью готовы запустить JavaScript, прежде чем делать это ...


2

Если вы используете webpack для рендеринга вашего реакции и используете HtmlWebpackPlugin в своем реакции, этот плагин создает свой пустой index.html сам по себе и внедряет в него файл js, поэтому он не содержит элемента div, так как HtmlWebpackPlugin docs вы можете создать свой собственный индекс. 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, не будут опубликованы. Я пришел к этому решению из этого SO ответа .


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 Ошибка: целевой контейнер не является элементом 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.