Skip to content

Commit 0cc374a

Browse files
committed
Deprecate ReactDOM.render and ReactDOM.hydrate
These are no longer supported in React 18. They are replaced by the `createRoot` API. The warning includes a link to documentation of the new API. Currently it redirects to the corresponding working group post. Here's the PR to set up the redirect: reactjs/react.dev#3730 Many of our tests still use ReactDOM.render. We will need to gradually migrate them over to createRoot. In the meantime, I added the warnings to our internal warning filter.
1 parent c6a4957 commit 0cc374a

File tree

9 files changed

+124
-28
lines changed

9 files changed

+124
-28
lines changed

fixtures/dom/src/__tests__/wrong-act-test.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,15 @@ it('warns when using the wrong act version - test + dom: render', () => {
101101
TestRenderer.act(() => {
102102
ReactDOM.render(<App />, document.createElement('div'));
103103
});
104-
}).toWarnDev(["It looks like you're using the wrong act()"], {
105-
withoutStack: true,
106-
});
104+
}).toWarnDev(
105+
[
106+
'ReactDOM.render is no longer supported in React 18.',
107+
"It looks like you're using the wrong act()",
108+
],
109+
{
110+
withoutStack: true,
111+
}
112+
);
107113
});
108114

109115
it('warns when using the wrong act version - test + dom: updates', () => {

packages/react-devtools-shared/src/__tests__/inspectedElement-test.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,8 @@ describe('InspectedElement', () => {
390390
});
391391

392392
const container = document.createElement('div');
393-
await utils.actAsync(() =>
394-
ReactDOM.render(<Target a={1} b="abc" />, container),
395-
);
393+
const root = ReactDOM.createRoot(container);
394+
await utils.actAsync(() => root.render(<Target a={1} b="abc" />));
396395

397396
expect(targetRenderCount).toBe(1);
398397
expect(console.error).toHaveBeenCalledTimes(1);

packages/react-dom/src/__tests__/ReactDOMFiber-test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,9 +1154,15 @@ describe('ReactDOMFiber', () => {
11541154
expect(ops).toEqual(['A']);
11551155

11561156
if (__DEV__) {
1157-
// TODO: this warning shouldn't be firing in the first place if user didn't call it.
11581157
const errorCalls = console.error.calls.count();
1159-
for (let i = 0; i < errorCalls; i++) {
1158+
expect(console.error.calls.argsFor(0)[0]).toMatch(
1159+
'ReactDOM.render is no longer supported in React 18',
1160+
);
1161+
expect(console.error.calls.argsFor(1)[0]).toMatch(
1162+
'ReactDOM.render is no longer supported in React 18',
1163+
);
1164+
// TODO: this warning shouldn't be firing in the first place if user didn't call it.
1165+
for (let i = 2; i < errorCalls; i++) {
11601166
expect(console.error.calls.argsFor(i)[0]).toMatch(
11611167
'unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.',
11621168
);

packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -787,16 +787,22 @@ describe('ReactErrorBoundaries', () => {
787787

788788
it('logs a single error when using error boundary', () => {
789789
const container = document.createElement('div');
790-
expect(() =>
791-
ReactDOM.render(
792-
<ErrorBoundary>
793-
<BrokenRender />
794-
</ErrorBoundary>,
795-
container,
796-
),
797-
).toErrorDev('The above error occurred in the <BrokenRender> component:', {
798-
logAllErrors: true,
799-
});
790+
spyOnDev(console, 'error');
791+
ReactDOM.render(
792+
<ErrorBoundary>
793+
<BrokenRender />
794+
</ErrorBoundary>,
795+
container,
796+
);
797+
if (__DEV__) {
798+
expect(console.error).toHaveBeenCalledTimes(2);
799+
expect(console.error.calls.argsFor(0)[0]).toContain(
800+
'ReactDOM.render is no longer supported',
801+
);
802+
expect(console.error.calls.argsFor(1)[0]).toContain(
803+
'The above error occurred in the <BrokenRender> component:',
804+
);
805+
}
800806

801807
expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
802808
expect(Scheduler).toHaveYielded([

packages/react-dom/src/__tests__/ReactErrorLoggingRecovery-test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ describe('ReactErrorLoggingRecovery', () => {
4343

4444
beforeEach(() => {
4545
console.error = error => {
46+
if (
47+
typeof error === 'string' &&
48+
error.includes('ReactDOM.render is no longer supported in React 18')
49+
) {
50+
// Ignore legacy root deprecation warning
51+
return;
52+
}
4653
throw new Error('Buggy console.error');
4754
};
4855
});

packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -668,16 +668,22 @@ describe('ReactLegacyErrorBoundaries', () => {
668668

669669
it('logs a single error using both error boundaries', () => {
670670
const container = document.createElement('div');
671-
expect(() =>
672-
ReactDOM.render(
673-
<BothErrorBoundaries>
674-
<BrokenRender />
675-
</BothErrorBoundaries>,
676-
container,
677-
),
678-
).toErrorDev('The above error occurred in the <BrokenRender> component', {
679-
logAllErrors: true,
680-
});
671+
spyOnDev(console, 'error');
672+
ReactDOM.render(
673+
<BothErrorBoundaries>
674+
<BrokenRender />
675+
</BothErrorBoundaries>,
676+
container,
677+
);
678+
if (__DEV__) {
679+
expect(console.error).toHaveBeenCalledTimes(2);
680+
expect(console.error.calls.argsFor(0)[0]).toContain(
681+
'ReactDOM.render is no longer supported',
682+
);
683+
expect(console.error.calls.argsFor(1)[0]).toContain(
684+
'The above error occurred in the <BrokenRender> component:',
685+
);
686+
}
681687

682688
expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
683689
expect(log).toEqual([
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
let ReactDOM = require('react-dom');
2+
3+
describe('ReactDOMRoot', () => {
4+
let container;
5+
6+
beforeEach(() => {
7+
jest.resetModules();
8+
container = document.createElement('div');
9+
ReactDOM = require('react-dom');
10+
});
11+
12+
test('deprecation warning for ReactDOM.render', () => {
13+
spyOnDev(console, 'error');
14+
15+
ReactDOM.render('Hi', container);
16+
expect(container.textContent).toEqual('Hi');
17+
if (__DEV__) {
18+
expect(console.error).toHaveBeenCalledTimes(1);
19+
expect(console.error.calls.argsFor(0)[0]).toContain(
20+
'ReactDOM.render is no longer supported',
21+
);
22+
}
23+
});
24+
25+
test('deprecation warning for ReactDOM.hydrate', () => {
26+
spyOnDev(console, 'error');
27+
28+
container.innerHTML = 'Hi';
29+
ReactDOM.hydrate('Hi', container);
30+
expect(container.textContent).toEqual('Hi');
31+
if (__DEV__) {
32+
expect(console.error).toHaveBeenCalledTimes(1);
33+
expect(console.error.calls.argsFor(0)[0]).toContain(
34+
'ReactDOM.hydrate is no longer supported',
35+
);
36+
}
37+
});
38+
});

packages/react-dom/src/client/ReactDOMLegacy.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,15 @@ export function hydrate(
219219
container: Container,
220220
callback: ?Function,
221221
) {
222+
if (__DEV__) {
223+
console.error(
224+
'ReactDOM.hydrate is no longer supported in React 18. Use createRoot ' +
225+
'instead. Until you switch to the new API, your app will behave as ' +
226+
"if it's running React 17. Learn " +
227+
'more: https://reactjs.org/link/switch-to-createroot',
228+
);
229+
}
230+
222231
invariant(
223232
isValidContainer(container),
224233
'Target container is not a DOM element.',
@@ -250,6 +259,15 @@ export function render(
250259
container: Container,
251260
callback: ?Function,
252261
) {
262+
if (__DEV__) {
263+
console.error(
264+
'ReactDOM.render is no longer supported in React 18. Use createRoot ' +
265+
'instead. Until you switch to the new API, your app will behave as ' +
266+
"if it's running React 17. Learn " +
267+
'more: https://reactjs.org/link/switch-to-createroot',
268+
);
269+
}
270+
253271
invariant(
254272
isValidContainer(container),
255273
'Target container is not a DOM element.',

scripts/jest/shouldIgnoreConsoleError.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ module.exports = function shouldIgnoreConsoleError(format, args) {
1313
// Ignore it too.
1414
return true;
1515
}
16+
if (
17+
format.indexOf('ReactDOM.render is no longer supported in React 18') !==
18+
-1 ||
19+
format.indexOf(
20+
'ReactDOM.hydrate is no longer supported in React 18'
21+
) !== -1
22+
) {
23+
// We haven't finished migrating our tests to use createRoot.
24+
return true;
25+
}
1626
}
1727
} else {
1828
if (

0 commit comments

Comments
 (0)