The typical way to trigger this warning is to call createRoot
multiple times on the same root:
ReactDOM.createRoot(document.querySelector("#app"))
.render(<p>A</p>);
ReactDOM.createRoot(document.querySelector("#app"))
.render(<p>B</p>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
You can see that the B
render overwrites the A
render.
If you want to run two different React apps, use different roots:
ReactDOM.createRoot(document.querySelector("#app-a"))
.render(<p>A</p>);
ReactDOM.createRoot(document.querySelector("#app-b"))
.render(<p>B</p>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app-a"></div>
<div id="app-b"></div>
Otherwise, if you're trying to render different components in the same app, render once with a single root component and render child components inside the root's subtree. This is the common case; most pages use one React app.
In most cases, createRoot
acts as an up front, one time set up for the whole React app that persists for the duration of the user's visit to the page. Rendering conditions go inside the component tree, and the element you want to render in is specified in the component as JSX.
For example:
const A = () => <p>A</p>;
const B = () => <p>B</p>;
const App = () => <React.Fragment><A /><B /></React.Fragment>;
ReactDOM.createRoot(document.querySelector("#app"))
.render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
If, for some reason, you want to render into that root multiple times, you can, as long as you limit yourself to one createRoot
call per root:
const root = ReactDOM.createRoot(document.querySelector("#app"));
root.render(<p>A</p>);
// silly example
setTimeout(() => root.render(<p>B</p>), 2000);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
Another possibility is you're looking for a portal that lets you escape the React DOM tree and render a component elsewhere. As above, though, there's stll one createRoot
and one render
and we use portals to put the component in a specfic element.
For example:
const A = () => <p>A</p>;
const B = () => ReactDOM.createPortal(
<p>B</p>,
document.querySelector("#portal")
);
const App = () => <React.Fragment><A /><B /></React.Fragment>;
ReactDOM.createRoot(document.querySelector("#app"))
.render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
<div id="portal"></div>
Portals are often seen in modals.
For completeness, another uncommon way to trigger this is by including Babel twice, as can occur in a Stack Snippet that has babel: true
as well as an import:
ReactDOM.createRoot(document.querySelector("#app"))
.render(<p>test</p>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
Which is more or less the same as:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
<script type="text/babel">
ReactDOM.createRoot(document.querySelector("#app"))
.render(<p>test</p>);
</script>