Pelanggaran Invarian: _registerComponent (...): Wadah target bukan elemen DOM

388

Saya mendapatkan kesalahan ini setelah membuat halaman contoh Bereaksi sepele:

Kesalahan Tidak Tertangkap: Pelanggaran Invarian: _registerComponent (...): Wadah target bukan elemen DOM.

Ini kode saya:

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

Apa artinya ini?

Dan Abramov
sumber
8
@go-oleg: Ini adalah notasi pendek ES6. Ini bukan masalah karena alat reaksi memiliki ES6 transpiler. Lihat di sini
Dan Abramov
14
Saya mengalami kesalahan yang sama, dan seperti yang orang lain sarankan, itu karena file bundle.js Anda memuat terlalu dini. Pindahkan tag <script> Anda ke badan (sebagai baris terakhir sebelum tag penutup </body>) untuk menyelesaikan kesalahan ini.
Todd R
2
itu tidak membantu di sini
daslicht
@daslicht Saya harap Anda menemukan jawaban Anda tetapi hanya itu dikatakan: GANDA PERIKSA bahwa Anda tidak mencampuradukkan kelas dan id. document.getElementById ("foo") tidak akan pernah, pernah, akan menemukan tag yang bertuliskan <div class = "foo">
Dave Kanter

Jawaban:

626

Pada saat skrip dijalankan, documentelemen belum tersedia, karena skrip scriptitu sendiri ada di head. Meskipun ini merupakan solusi yang valid untuk disimpan dan scriptdi head- render pada DOMContentLoadedacara , itu lebih baik untuk menempatkan Anda scriptdi bagian paling bawah body dan membuat komponen root ke divsebelum seperti ini:

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

dan di bundle.js, hubungi:

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

Anda harus selalu membuat yang bersarang divalih-alih body. Jika tidak, semua jenis kode pihak ketiga (Google Font Loader, plugin browser, apa pun) dapat memodifikasi bodysimpul DOM ketika Bereaksi tidak mengharapkannya, dan menyebabkan kesalahan aneh yang sangat sulit dilacak dan didebug. Baca lebih lanjut tentang masalah ini.

Yang menyenangkan tentang menempatkan scriptdi bagian bawah adalah bahwa ia tidak akan memblokir rendering hingga skrip dimuat jika Anda menambahkan React server rendering ke proyek Anda.


Pembaruan: (07 Oktober 2015 | v0.14 )

React.rendersudah usang, gunakan ReactDOM.render saja.

Contoh:

import ReactDOM from 'react-dom';

ReactDOM.render(<App />, document.getElementById('root'));
Dan Abramov
sumber
3
Saya menggunakan pernyataan impor di webpack dan masih mendapatkan kesalahan ini. Saya pikir webpack akan mengurus urutan pemuatan skrip tidak?
thetrystero
4
Pertimbangkan untuk menggunakan defer <script defer src = " fb.me/react-0.14.7.js " ></script> <script defer src =" fb.me/react-dom-0.14.7.js"></ script > <! - kode aplikasi Anda sekarang -> <script defer src = "app.js"> </script> </body>
mendarat
4
@thetrystero Tidak, webpack tidak memiliki pengetahuan tentang tempat relatif bundel aplikasi Anda dengan node DOM yang dioperasikannya.
Dan Abramov
1
Kesalahan samar seperti itu - hanya menempatkan skrip di bawah root div membuatnya bekerja ...
kchoi
1
Ini bukan kasus @DanAbramov tapi saya menerima kesalahan yang sama dengan menggunakan wadah target tanpa tag penutup lengkap (misalnya <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 +)

Catatan : Setelah <script async src="..."></script>di header memastikan bahwa browser akan mulai mengunduh bundel JavaScript sebelum konten HTML dimuat.

Sumber: React Starter Kit , isomorphic-style-loader

Konstantin Tarkus
sumber
5
Itu ReactDOM.renderbukan React.render.
Conrado Fonseca
Catatan peringatan: jika Anda mengatur reaksi Anda untuk memuat secara tidak sinkron, itu menciptakan kondisi balapan - jika browser selesai mengurai halaman sebelum JS dieksekusi, Anda baik-baik saja. Jika JS dimuat sebelum halaman diuraikan, Anda akan berakhir dengan masalah yang sama dengan pertanyaan. defermungkin menjadi pilihan yang lebih baik
BRasmussen
16

yang fungsi siap dapat digunakan seperti ini:

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

Jika Anda tidak ingin menggunakan jQuery, Anda dapat menggunakan onloadfungsi ini:

<body onload="initReact()">...</body>
nils petersohn
sumber
6
Saya pikir DOMContentLoadedakan lebih tepat bahkan untuk menangani daripada load(ini adalah apa yang menggunakan jQuery ). Anda juga dapat melakukan ini di JS dengan window.addEventListener, tidak perlu penangan inline dan fungsi global.
Dan Abramov
3
Catatan, renderComponent akan didepresiasi. Gunakan React.render () sebagai gantinya.
Tommyixi
2
Saya menggunakan reaksi-rel sehingga memindahkan tag skrip ke bawah tag tubuh bukanlah pilihan. $(document).readymemecahkan masalah. Oh dan ya gunakan rendersaja renderComponent.
ltrainpr
1
Ini praktik yang sangat buruk untuk menggunakan jQuery dengan Bereaksi. Gunakan salah satu, tetapi tidak keduanya sekaligus.
aggregate1166877
11

tebak saja, bagaimana kalau menambahkan ke index.html berikut ini:

type="javascript"

seperti ini:

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

Bagi saya itu berhasil! :-)

taquiles
sumber
3
Hanya FYI, ini menyebabkan masalah bagi saya di mana type="text/javascript"bekerja dengan baik.
steezeburger
Itu mengerikan yang sebenarnya memperbaiki masalah saya. agak sedih, tetapi tidak yakin siapa yang harus disalahkan atas hal ini, bereaksi atau babel?
William Howley
6

Saya mengalami kesalahan yang sama. Ternyata disebabkan oleh kesalahan ketik sederhana setelah mengubah kode saya dari:

document.getElementById('root')

untuk

document.querySelector('root')

Perhatikan '#' yang hilang itu seharusnya

document.querySelector('#root')

Hanya memposting kalau-kalau itu membantu orang lain mengatasi kesalahan ini.

mangakid
sumber
4

Ya, pada dasarnya apa yang Anda lakukan benar, kecuali Anda lupa bahwa JavaScript disinkronkan dalam banyak kasus, jadi Anda menjalankan kode sebelum DOM Anda dimuat, ada beberapa cara untuk menyelesaikan ini:

1) Periksa untuk melihat apakah DOM dimuat penuh, kemudian lakukan apa pun yang Anda inginkan, Anda dapat mendengarkan DOMContentLoaded misalnya:

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

2) Cara paling umum adalah menambahkan tag skrip ke bagian bawah document(setelah tag body) Anda:

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

3) Menggunakan window.onload, yang dipecat ketika seluruh halaman dimuat (img, dll)

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

4) Menggunakan document.onload, yang dipecat ketika DOM siap:

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

Bahkan ada lebih banyak opsi untuk memeriksa apakah DOM sudah siap, tetapi jawaban singkatnya adalah JANGAN menjalankan skrip apa pun sebelum Anda memastikan DOM Anda siap dalam setiap kasus ...

JavaScript bekerja bersama dengan elemen DOM dan jika tidak tersedia, akan kembali nol , dapat merusak seluruh aplikasi ... jadi selalu pastikan Anda sepenuhnya siap untuk menjalankan JavaScript sebelum melakukannya ...

Alireza
sumber
2

Jika Anda menggunakan webpack untuk merender reaksi Anda dan menggunakan HtmlWebpackPlugin dalam reaksi Anda, plugin ini membangun index.html kosong dengan sendirinya dan menyuntikkan file js di dalamnya, sehingga tidak mengandung elemen div, karena dokumen HtmlWebpackPlugin Anda dapat membuat indeks Anda sendiri. html dan berikan alamatnya ke plugin ini, di webpack.config.js saya

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

dan ini adalah file index.html saya

<!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
sumber
1
Mengapa menggunakan HtmlWebpackPluginplugin di sini jika digunakan untuk referensi file HTML statis?
Harry Cho
1

Dalam kasus saya kesalahan ini disebabkan oleh reload panas, saat memperkenalkan kelas baru. Pada tahap proyek tersebut, gunakan pengamat normal untuk mengkompilasi kode Anda.

Mikros
sumber
1

Bagi mereka yang menggunakan ReactJS.Net dan mendapatkan kesalahan ini setelah dipublikasikan:

Periksa properti file .jsx Anda dan pastikan Build Actiondiatur ke Content. Yang diatur Nonetidak akan dipublikasikan. Saya menemukan solusi ini dari jawaban SO ini .

Jecom
sumber
1

Saya mengalami pesan kesalahan yang sama / sama. Dalam kasus saya, saya tidak memiliki node DOM target yang membuat komponen ReactJS didefinisikan. Pastikan node target HTML didefinisikan dengan baik dengan "id" atau "nama" yang sesuai, bersama dengan atribut HTML lainnya (cocok untuk kebutuhan desain Anda)

anie codeskol
sumber
Saya memiliki masalah serupa. Dalam pandangan saya memiliki pernyataan <code> jika </code> di mana elemen target yang diharapkan harus dihasilkan jika kondisi terpenuhi. Dalam kasus saya elemen yang tepat bukan render karena kondisi, tetapi skrip dieksekusi dan mencoba untuk me-mount komponen pada elemen yang tidak ada di DOM.
Rafal Cypcer
0

mudah saja buat js HTML CSS dasar dan render skrip dari 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
sumber
0

Ketika Anda mendapat:

Kesalahan: Kesalahan Tidak Tertangkap: Wadah target bukan elemen DOM.

Anda dapat menggunakan acara DOMContentLoaded atau memindahkan <script ...></script>tag Anda di bagian bawah tubuh Anda.

Acara DOMContentLoaded menyala ketika dokumen HTML awal telah dimuat dan diurai sepenuhnya, tanpa menunggu stylesheet, gambar, dan subframe selesai dimuat.

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