javascriptreactjsreact-dom

Uncaught (in promise) Error: Target container is not a DOM element


I have a React app with below dependencies:

"react": "~17.0.0",
"react-dom": "~17.0.0",

In my src/index.js, I have:

import('./bootstrap');
export { };

In src/bootstrap.jsx, I have:

import ReactDOM from 'react-dom';
import App from './components/App';

const container = document.getElementById('root');
const root = ReactDOM.render(container);

root.render(<App />);

In public/index.html, I already have a div with id "root" as below:

<!DOCTYPE html>
<html lang="en" class="dark">
<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <link rel="icon" type="image/png" href="%PUBLIC_URL%/logo64.png" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta http-equiv="cache-control" content="max-age=0" />
  <meta http-equiv="cache-control" content="no-cache" />
  <meta http-equiv="expires" content="0" />
  <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
  <meta http-equiv="pragma" content="no-cache" />
  <meta name="theme-color" content="#161616" />
  <meta
    name="description"
    content="my-host-ui"
  />
  <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
  <link rel="manifest" crossorigin="use-credentials" href="%PUBLIC_URL%/manifest.json" />
  <title>my-host-ui</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

The build works and I am able to start the app, but I get the following error in the browser console:

Uncaught (in promise) Error: Target container is not a DOM element.

From what I read, it is mostly because of the DOM element missing in index.html, but in this case, I already have the DOM element with id "root".

I have replaced this code from an upgraded project (on React v18), which has the code as below

import ReactDOM from 'react-dom';

const container = document.getElementById('root');
const root = ReactDOM.render(container);

root.render(<BootstrapApp />);

Solution

  • The problem is here:

    const container = document.getElementById('root');
    const root = ReactDOM.render(container); // <====
    
    root.render(<BootstrapApp />); // (This is also incorrect)
    

    Live example of the error:

    const BootstrapApp = () => {
        return <div>App</div>;
    };
    
    try {
        const container = document.getElementById("root");
        const root = ReactDOM.render(container);
    
        root.render(<BootstrapApp />);
    } catch (error) {
        console.error(error.stack);
    }
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

    That isn't how you bootstrap a React app with v17, it's like a cross between the old v17 and earlier way and the v18+ way. You get the error because you're not passing a second argument to ReactDOM.render, so it gets undefined, so you get the error.

    The correct v17 and earlier way is:

    const container = document.getElementById("root");
    ReactDOM.render(<BootstrapApp />, container);
    

    or simply:

    ReactDOM.render(<BootstrapApp />, document.getElementById("root"));
    

    Live example:

    const BootstrapApp = () => {
        return <div>App</div>;
    };
    
    ReactDOM.render(<BootstrapApp />, document.getElementById("root"));
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

    For completeness, the correct v18+ way is:

    import { createRoot } from "react-dom/client";
    // ...
    const root = createRoot(document.getElementById("root"));
    root.render(<BootstrapApp />);
    

    or simply:

    import { createRoot } from "react-dom/client";
    // ...
    createRoot(document.getElementById("root")).render(<BootstrapApp />);
    

    Live example:

    const BootstrapApp = () => {
        return <div>App</div>;
    };
    
    // Note: Can't use `import` version, so we use `ReactDOM` here
    ReactDOM.createRoot(document.getElementById("root")).render(<BootstrapApp />);
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>