Vi phạm bất biến: _registerComponent (Mạnh): Container mục tiêu không phải là thành phần DOM


388

Tôi gặp lỗi này sau khi tạo một trang ví dụ React tầm thường:

Uncaught Error: Invariant Vi phạm: _registerComponent (...): Container mục tiêu không phải là một thành phần DOM.

Đây là mã của tôi:

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

Điều đó có nghĩa là gì?


8
@ go-oleg: Đây là ký hiệu ngắn ES6. Đây không phải là vấn đề vì các công cụ phản ứng có bộ chuyển mã ES6. Xem tại đây
Dan Abramov

14
Tôi gặp phải lỗi tương tự và như những người khác đã đề xuất, đó là do tệp bundle.js của bạn đang tải quá sớm. Di chuyển thẻ <script> của bạn vào phần thân (là dòng cuối cùng trước thẻ đóng </ body>) để khắc phục lỗi này.
Todd R

2
Điều đó không giúp được gì ở đây
daslicht

@daslicht Tôi hy vọng bạn đã tìm thấy câu trả lời của mình nhưng chỉ cần nói rằng: KIỂM TRA NHÂN ĐÔI rằng bạn không trộn lẫn các lớp và id. document.getEuityById ("foo") sẽ không bao giờ tìm thấy một thẻ đọc <div class = "foo">
Dave Kanter

Câu trả lời:


626

Theo kịch bản thời gian được thực thi, documentphần tử chưa có sẵn, bởi vì scriptchính nó nằm trong head. Trong khi đó là một giải pháp hợp lệ để giữ scripttrong headhiển thị trên DOMContentLoadedsự kiện , nó thậm chí còn tốt hơn để đưa bạn scriptvào rất đáy body làm cho thành phần gốc để một divtrước khi nó như thế này:

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

và trong bundle.js, gọi:

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

Bạn nên luôn luôn kết xuất thành một lồng divthay vì body. Mặt khác, tất cả các loại mã của bên thứ ba (Google Font Loader, plugin trình duyệt, bất cứ thứ gì) đều có thể sửa đổi bodynút DOM khi React không mong đợi nó và gây ra các lỗi lạ rất khó theo dõi và gỡ lỗi. Đọc thêm về vấn đề này.

Điều thú vị khi đặt scriptở dưới cùng là nó sẽ không chặn kết xuất cho đến khi tải tập lệnh trong trường hợp bạn thêm kết xuất máy chủ React vào dự án của mình.


Cập nhật: (ngày 07 tháng 10 năm 2015 | v0,14 )

React.renderđược phản đối, sử dụng ReactDOM.render thay thế.

Thí dụ:

import ReactDOM from 'react-dom';

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

3
Tôi đang sử dụng báo cáo nhập khẩu trong webpack và vẫn gặp lỗi này. Tôi nghĩ webpack sẽ chăm sóc thứ tự tải tập lệnh không?
th temstero

4
Cân nhắc sử dụng defer <script defer src = " fb.me/react-0.14.7.js " ></script> <script defer src =" fb.me/react-dom-0.14.7.js"></ script > <! - mã ứng dụng của bạn ngay bây giờ -> <script defer src = "app.js"> </ script> </ body>
đã hạ cánh

4
@th temstero Không, webpack không có kiến ​​thức về vị trí tương đối của gói ứng dụng của bạn với các nút DOM mà nó hoạt động.
Dan Abramov

1
Lỗi khó hiểu như vậy - chỉ cần đặt tập lệnh bên dưới div gốc đã khiến nó hoạt động ...
kchoi

1
Đó không phải là trường hợp của @DanAbramov nhưng tôi đã nhận được lỗi tương tự bằng cách sử dụng bộ chứa đích mà không có thẻ đóng hoàn chỉnh (ví dụ <phần 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 +)

Lưu ý : Có <script async src="..."></script>trong tiêu đề đảm bảo rằng trình duyệt sẽ bắt đầu tải xuống gói JavaScript trước tải nội dung HTML.

Nguồn: React Starter Kit , bộ nạp kiểu đẳng cấu


5
Nó là ReactDOM.renderthay vì React.render.
Conrado Fonseca

Lưu ý cảnh báo: nếu bạn đặt phản ứng của mình tải không đồng bộ, nó sẽ tạo điều kiện chạy đua - nếu trình duyệt hoàn thành phân tích cú pháp trang trước khi thực thi JS, bạn vẫn ổn. Nếu JS được tải trước khi trang được phân tích cú pháp, bạn sẽ kết thúc với cùng một vấn đề mà câu hỏi đặt ra. defercó thể là một lựa chọn tốt hơn
BRasmussen

16

các chức năng sẵn sàng có thể được sử dụng như thế này:

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

Nếu bạn không muốn sử dụng jQuery, bạn có thể sử dụng onloadhàm:

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

6
Tôi nghĩ DOMContentLoadedthậm chí sẽ thích hợp hơn để xử lý hơn load(đây là những gì jQuery sử dụng ). Bạn cũng có thể làm điều này trong JS với window.addEventListener, không cần trình xử lý nội tuyến và các hàm toàn cục.
Dan Abramov

3
Lưu ý, renderComponent sẽ bị khấu hao. Sử dụng React.render () thay thế.
Tommyixi 17/03/2015

2
Tôi đang sử dụng ray phản ứng nên việc di chuyển thẻ script xuống dưới cùng của thẻ body không phải là một tùy chọn. $(document).readyĐã giải quyết vấn đề. Oh và có sử dụng renderthay vì renderComponent.
ltrainpr

1
Việc sử dụng jQuery với React là một cách cực kỳ tồi tệ. Sử dụng một trong hai, nhưng không phải cả hai cùng một lúc.
tổng

11

chỉ là một phỏng đoán hoang dã, làm thế nào về việc thêm vào index.html như sau:

type="javascript"

như thế này:

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

Đối với tôi nó đã làm việc! :-)


3
Chỉ cần FYI, điều này gây ra vấn đề cho tôi khi type="text/javascript"làm việc đúng.
steezeburger

Đó là khủng khiếp mà thực sự đã khắc phục vấn đề của tôi. Loại buồn, nhưng không chắc ai sẽ đổ lỗi cho cái này, phản ứng hay babel?
William Howley

6

Tôi chạy vào cùng một lỗi. Hóa ra là do một lỗi đánh máy đơn giản sau khi thay đổi mã của tôi từ:

document.getElementById('root')

đến

document.querySelector('root')

Lưu ý thiếu '#' Đáng lẽ phải có

document.querySelector('#root')

Chỉ cần đăng trong trường hợp nó giúp bất cứ ai khác giải quyết lỗi này.


4

Đúng, về cơ bản những gì bạn đã làm là đúng, ngoại trừ bạn quên rằng JavaScript được đồng bộ hóa trong nhiều trường hợp, vì vậy bạn chạy mã trước DOM của mình được tải, có một số cách để giải quyết điều này:

1) Kiểm tra xem DOM đã được tải đầy đủ chưa, sau đó làm bất cứ điều gì bạn muốn, bạn có thể nghe DOMContentLoaded chẳng hạn:

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

2) Cách rất phổ biến là thêm thẻ script vào cuối documentthẻ (sau thẻ body):

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

3) Sử dụng window.onload, được kích hoạt khi toàn bộ trang được tải (img, v.v.)

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

4) Sử dụng document.onload, được bắn khi DOM sẵn sàng:

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

Thậm chí còn có nhiều tùy chọn hơn để kiểm tra xem DOM đã sẵn sàng chưa, nhưng câu trả lời ngắn gọn là KHÔNG chạy bất kỳ tập lệnh nào trước khi bạn đảm bảo DOM của bạn đã sẵn sàng trong mọi trường hợp ...

JavaScript đang hoạt động cùng với các phần tử DOM và nếu chúng không có sẵn, sẽ trả về null , có thể phá vỡ toàn bộ ứng dụng ... vì vậy hãy luôn đảm bảo rằng bạn đã sẵn sàng để chạy JavaScript trước khi bạn ...


2

Nếu bạn sử dụng gói web để hiển thị phản ứng của bạn và sử dụng HtmlWebpackPlugin trong phản ứng của bạn, thì plugin này tự xây dựng index.html trống của nó và tiêm tệp js vào nó, vì vậy nó không chứa phần tử div, vì tài liệu HtmlWebpackPlugin bạn có thể xây dựng chỉ mục của riêng mình. html và cung cấp địa chỉ của nó cho plugin này, trong webpack.config.js của tôi

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

và đây là tệp index.html của tôi

<!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
Tại sao nên sử dụng HtmlWebpackPluginplugin ở đây nếu nó được sử dụng để tham chiếu tệp HTML tĩnh?
Harry Cho

1

Trong trường hợp của tôi, lỗi này là do tải lại nóng, trong khi giới thiệu các lớp mới. Trong giai đoạn đó của dự án, sử dụng các trình theo dõi bình thường để biên dịch mã của bạn.


1

Đối với những người sử dụng ReactJS.Net và gặp lỗi này sau khi xuất bản:

Kiểm tra các thuộc tính của tệp .jsx của bạn và đảm bảo Build Actionđược đặt thành Content. Những người thiết lập Nonesẽ không được công bố. Tôi đã tìm ra giải pháp này từ câu trả lời SO này .


1

Tôi chạy vào thông báo lỗi tương tự / tương tự. Trong trường hợp của tôi, tôi không có nút DOM đích để hiển thị thành phần ReactJS được xác định. Đảm bảo nút mục tiêu HTML được xác định rõ với "id" hoặc "name" thích hợp, cùng với các thuộc tính HTML khác (phù hợp với nhu cầu thiết kế của bạn)


Tôi đã có vấn đề tương tự. Trong chế độ xem, tôi có câu lệnh <code> if </ code> trong đó phần tử đích dự kiến ​​sẽ được tạo nếu điều kiện được đáp ứng. Trong trường hợp của tôi, phần tử thích hợp không được hiển thị vì điều kiện, nhưng tập lệnh được thực thi và cố gắng gắn kết thành phần trên phần tử không tồn tại trong DOM.
Cypcer

0

thật dễ dàng chỉ cần tạo js CSS HTML cơ bản và hiển thị tập lệnh từ 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

Khi bạn có:

Lỗi: Uncaught Error: Target container không phải là phần tử DOM.

Bạn có thể sử dụng sự kiện DOMContentLoaded hoặc di chuyển <script ...></script>thẻ của bạn ở dưới cùng của cơ thể.

Sự kiện DOMContentLoaded kích hoạt khi tài liệu HTML ban đầu đã được tải và phân tích cú pháp hoàn toàn, không cần chờ biểu định kiểu, hình ảnh và khung con để tải xong.

document.addEventListener("DOMContentLoaded", function(event) {
  ReactDOM.render(<App />, document.getElementById('root'));
})
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.