How to fix Warning: ReactDOM.render() does not return a reference to the returned component instance in React
This warning appears when attempting to use the return value of ReactDOM.render() to access a component instance. React warns against this because it is a legacy pattern that may not work with future async rendering features.
Quick fix
Fixes Warning: ReactDOM.render() does not return a reference to the returned component instance
// Before (legacy pattern)
const componentInstance = ReactDOM.render(
<MyComponent />,
document.getElementById('root')
);
componentInstance.someMethod();
// After (recommended pattern)
let componentInstance;
ReactDOM.render(
<MyComponent ref={(ref) => { componentInstance = ref; }} />,
document.getElementById('root')
);
// Use componentInstance after it's set
if (componentInstance) {
componentInstance.someMethod();
}- Use a callback ref to access the component instance
- Migrate to React 18 createRoot API
- Refactor to avoid needing component references
- Use React Context for cross-component communication
// Before (legacy pattern)const componentInstance = ReactDOM.render(<MyComponent />,document.getElementById('root'));componentInstance.someMethod();// After (recommended pattern)let componentInstance;ReactDOM.render(<MyComponent ref={(ref) => { componentInstance = ref; }} />,document.getElementById('root'));// Use componentInstance after it's setif (componentInstance) {componentInstance.someMethod();}Warning: ReactDOM.render() does not return a reference to the returned component instance
What this error means
This warning indicates that you are trying to use the return value of ReactDOM.render() to get a reference to the rendered component instance. While ReactDOM.render() historically returned a reference to the root component (for class components), this behavior is being deprecated because it is incompatible with React's concurrent rendering features. In React 17 and earlier, ReactDOM.render() could return a component instance for class components, allowing direct access to the component's methods and state. However, this pattern was never recommended and becomes problematic with React 18's concurrent rendering, where components may render asynchronously. This means the component might not be fully mounted when ReactDOM.render() returns, creating race conditions. The React team has deprecated this pattern in favor of using refs, which provide a more reliable and future-proof way to access component instances. In React 18 and later, you should migrate to the createRoot API, which does not return a component reference at all.
Typical symptoms
- Warning message appears in browser console when using ReactDOM.render() return value
- Code attempts to access component methods or state through the render() return value
- Application works but displays deprecation warnings
- ESLint rule react/no-render-return-value triggers if configured
Common causes
- Using the return value of ReactDOM.render() to access component instance
- Legacy code pattern from older React versions that relied on render() return value
- Storing ReactDOM.render() result in a variable for later component access
- Calling component methods directly through the render() return value
- Using React 18+ with legacy rendering patterns
How to fix "Warning: ReactDOM.render() does not return a reference to the returned component instance"
The recommended approach is to use a callback ref attached to your root component:
// Before (legacy pattern)
const componentInstance = ReactDOM.render(
<MyComponent />,
document.getElementById('root')
);
componentInstance.someMethod();
// After (recommended pattern)
let componentInstance;
ReactDOM.render(
<MyComponent ref={(ref) => { componentInstance = ref; }} />,
document.getElementById('root')
);
// Use componentInstance after it's set
if (componentInstance) {
componentInstance.someMethod();
}The callback ref will be called with the component instance once it's mounted, providing safe access to the component.
If you're using React 18 or later, migrate to the new createRoot API which doesn't return a component reference:
// Legacy React 17
import ReactDOM from 'react-dom';
ReactDOM.render(<App />, document.getElementById('root'));
// React 18+
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);With createRoot, you should use refs within your component tree rather than accessing the root component externally.
Consider whether you actually need direct access to the component instance. Often, this pattern can be replaced with better React practices:
// Instead of calling methods on component instance
// Use state lifting and props
// Before
const app = ReactDOM.render(<App />, root);
app.updateData(newData);
// After - lift state up or use context
function Parent() {
const [data, setData] = useState(initialData);
return <App data={data} onUpdate={setData} />;
}
root.render(<Parent />);This approach is more idiomatic and works better with React's unidirectional data flow.
If you need to trigger actions or access data across your component tree, use React Context instead of component references:
const AppContext = React.createContext();
function App() {
const [state, setState] = useState(initialState);
const api = {
updateData: (data) => setState(data),
// other methods
};
return (
<AppContext.Provider value={api}>
<YourComponents />
</AppContext.Provider>
);
}
// In any child component
function ChildComponent() {
const { updateData } = useContext(AppContext);
return <button onClick={() => updateData(newData)}>Update</button>;
}Advanced notes
Why This Pattern Was Deprecated:
The return value of ReactDOM.render() creates tight coupling between the rendering logic and component internals, which goes against React's declarative programming model. With React 18's concurrent features, rendering can be interruptible and may not complete synchronously, making the return value unreliable.
React 19 Changes:
In React 19, the need for forwardRef is being reduced as refs can be passed as normal props. This simplifies ref handling throughout your application. However, the createRoot API remains the recommended approach for mounting React applications.
Integration Testing:
If you need component references for testing purposes, use testing libraries like React Testing Library which provide better APIs for interacting with rendered components without relying on internal references:
import { render, screen } from '@testing-library/react';
const { container } = render(<MyComponent />);
const element = screen.getByRole('button');Legacy Code Migration:
When migrating large codebases, you can gradually refactor code that uses render() return values. Start by identifying all instances where the return value is used (ESLint's react/no-render-return-value rule helps with this) and prioritize based on how frequently each component is accessed.
Frequently asked questions
- What does "Warning: ReactDOM.render() does not return a reference to the returned" mean?
- render() to get a reference to the rendered component instance. render() historically returned a reference to the root component (for class components), this behavior is being deprecated because it is incompatible with React's concurrent rendering features. render() could return a component instance for class components, allowing direct access to the component's methods and state.
- How do I fix "Warning: ReactDOM.render() does not return a reference to the returned"?
- This warning appears when attempting to use the return value of ReactDOM.render() to access a component instance. React warns against this because it is a legacy pattern that may not work with future async rendering features.
- What causes "Warning: ReactDOM.render() does not return a reference to the returned"?
- Using the return value of ReactDOM.render() to access component instance Legacy code pattern from older React versions that relied on render() return value Storing ReactDOM.render() result in a variable for later component access
- Is the "Warning: ReactDOM.render() does not return a reference to the returned" error serious?
- It is a low-severity error โ more of a blocker than a risk. The steps above resolve it.