React 18: Migrating from ReactDOM.render to createRoot
Problem
React 18 introduced significant changes to the rendering API, deprecating the traditional ReactDOM.render()
method. When using Create React App or updating existing projects, developers encounter this warning:
WARNING
Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17.
This occurs because the default index.js
file generated by older versions of Create React App uses the deprecated API:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Solution
React 18 replaces ReactDOM.render()
with a new root API using ReactDOM.createRoot()
. This change enables concurrent features and performance improvements in React 18.
Basic Migration
Update your index.js
file with the new API:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
Alternative Syntax
For a more concise approach:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
TypeScript Version
If using TypeScript, add proper type assertions:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
With React Router
If your app uses React Router, the migration is similar:
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
Using Named Imports
You can also use named imports for a cleaner approach:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
Key Differences
The new root API introduces several important changes:
- Concurrent Features:
createRoot()
enables concurrent rendering features - Error Handling: Improved error handling with error boundaries
- Hydration: Separate
hydrateRoot()
method for server-side rendering - Unmounting: New
root.unmount()
method instead ofReactDOM.unmountComponentAtNode()
INFO
While React 18 maintains backward compatibility with ReactDOM.render()
, it runs in a compatibility mode that doesn't support new features. For optimal performance and access to concurrent features, migrate to createRoot()
.
Deprecated APIs
React 18 deprecated several APIs alongside ReactDOM.render()
:
ReactDOM.hydrate
ReactDOM.unmountComponentAtNode
ReactDOM.renderSubtreeIntoContainer
ReactDOMServer.renderToNodeStream
Testing Library Compatibility
If you encounter issues with testing libraries, ensure you're using compatible versions:
npm i @testing-library/react@latest
Conclusion
Migrating from ReactDOM.render()
to createRoot()
is straightforward and essential for taking full advantage of React 18's performance improvements and new features. The change primarily involves:
- Updating the import from
react-dom
toreact-dom/client
- Creating a root with
ReactDOM.createRoot()
- Using
root.render()
instead ofReactDOM.render()
This migration future-proofs your application and ensures access to React's latest capabilities while eliminating deprecation warnings.