动态创建反应应用程序挂载的元素

Dynamically creating an element on which the react app mounts

我想使用 React 创建我的 javascript 应用程序的构建,它目前只是定义如下的单个文件。它除了创建一个 div 并在安装后不断更改 hello-world 文本的颜色外什么都不做。

import * as React from "react";
import * as ReactDOM from "react-dom";

class App extends React.Component {
    componentDidMount() {
        const colorBox = ["red","blue","green"];
        const element = document.getElementById("my-div");
        setInterval(() => {
            element.style.color = colorBox[parseInt(Math.floor(Math.random() * colorBox.length))];
        }, 3000);
    }

    render() {
        return (
            <div id={"my-div"}>
                Hello, World.
            </div>
        );
    }
}

ReactDOM.render(<App />,         
    document.body.appendChild(document.createElement("div")));

我正在使用 parcel js 作为捆绑器。我将我的 javascript 捆绑为 parcel build index.js,这会在 dist 文件夹中创建我的 javascript 文件的构建。到目前为止,一切都很好。但是那一刻,我在我的网站上使用脚本标签加载这个 javascript 作为:

<script type="text/javascript" src="https://mycdn.com/bundle.index.js"></script>

它抛出一个错误

    index.js:16 Uncaught TypeError: Cannot read property 'appendChild' of null
    at Object.parcelRequire.Focm.react (index.js:16)
    at f (index.js:1)
    at parcelRequire.YOwE (index.js:1)
    at index.js:1

为什么它无法访问 document.bodyappendChild?我还检查了 document.body 是否为空。这里发生了什么?我缺少什么?

首先,我不确定在包中包含直接影响页面的代码是否是个好主意。

我猜测为什么会发生这种情况,这与页面中加载包的时间有关。是在head吗?如果是这样 document.body 可能无法使用。

如果您要执行此类操作,最好使用与文档准备就绪相关的事件。

根据您的需要,这可能会变得复杂,但如果您可以访问 jQuery,则可以使用 .ready()

如果没有你可以使用various vanilla js options

我猜你的问题与捆绑有关,或者你在它可用之前要求一个元素,因为它在这里工作正常:https://jsfiddle.net/rL6dnhps

如果从头部加载它,请尝试将其放在主体的末尾以等待主体准备就绪或将其包裹在如下所示的 IIFE 中:

(function() {
    // the DOM will be available here
    ReactDOM.render(<App />,         
    document.body.appendChild(document.createElement("div")));
})();