With the React 18 update, thousands of React developers unexpectedly faced the following warning from within their applications, instructing us to use createRoot instead of ReactDOM.render:

Deprecation warning: ReactDOM.render is no longer supported in React 18
Let’s find out why this warning exists, and how to fix it in React 18.
Deprecation notice: ReactDOM.render is no longer supported in React 18. Use createRoot instead.
To fix the deprecation warning about ReactDOM.render
, you should update your index.js
file in your app’s root directory.
Here’s an example of an index.js
file that uses ReactDOM.render
, causing a deprecation notice:
// NOTE: This is deprecated code!
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App />,
document.getElementById('root')
);
To fix the error Deprecation notice: ReactDOM.render is no longer supported
you should edit your index.js
file to look like the following:
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);
ReactDOM.render vs. createRoot
ReactDOM.render
is a function that takes two parameters: a DOM element to be used as the app root and the component to be rendered inside of that root. ReactDOM.render
returns nothing.
createRoot
is function that takes a single parameter, and that is the DOM element to use as the root of the application. It returns an object with a render
method that can be used to render a React component inside of that root.
This new root API is more secure and efficient than ReactDOM.render
, even though it requires a pesky update to your index.js
.
Callbacks that run on rendering
With ReactDOM.render
, you were allowed to provide a callback function that would run whenever the app was finished rendering. Here’s an example of this in practice:
// NOTE: This is deprecated code!
import ReactDOM from 'react-dom';
import App from './src/App';
ReactDOM.render(
<App />,
document.getElementById('root'),
() => console.log('React App Rendered!')
);
This render callback is no longer a part of the root API with createRoot
, although you can still create similar effects with requestIdleCallback
, setTimeout
, or a traditional DOMContentLoaded
event.
No need to pass in the container on every render
If you wanted to run ReactDOM.render()
multiple times, that would mean passing in the DOM container multiple times as well.
With the new root API using createRoot
, you can create a single app root, passing in the container once, and render different React components on that same container.
How to use hydrate
with createRoot
The hydrate
function from the legacy root API has moved to a separate hydrateRoot
API.
// Legacy root API with ReactDOM.render
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.hydrate(
<App />,
document.getElementById('root')
);
// new root API with createRoot
import * as ReactDOMClient from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
const root = ReactDOMClient.hydrate(container, <App />);
What is a root in React?
In React, a root is the top-level DOM element that contains your entire application.
You can imagine the application root as the roots of a tree, while all of your components make up the branches. (Which really makes sense, seeing as how every React app has a “component tree.”) The root is where everything else has to be rendered in order to appear on the web page.

Why was ReactDOM.render deprecated?
The primary reason for the React 18 ReactDOM.render
deprecation is usability. As shown above, with createRoot
we can manage multiple calls to render()
with the same root and the same DOM container element, leading to less boilerplate code and a cleaner API.
If you’d like to become a master of React, head over to my YouTube channel, or start reading my article series on React.
One thought on “[FIXED!] ReactDOM Deprecation notice | ReactDOM.render vs. createRoot”