mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Deprecate ReactDOM.render and ReactDOM.hydrate (#21652)
* Use existing test warning filter for server tests We have a warning filter for our internal tests to ignore warnings that are too noisy or that we haven't removed from our test suite yet: shouldIgnoreConsoleError. Many of our server rendering tests don't use this filter, though, because it has its own special of asserting warnings. So I added the warning filter to the server tests, too. * 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: https://github.com/reactjs/reactjs.org/pull/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.
This commit is contained in:
@@ -101,9 +101,15 @@ it('warns when using the wrong act version - test + dom: render', () => {
|
||||
TestRenderer.act(() => {
|
||||
ReactDOM.render(<App />, document.createElement('div'));
|
||||
});
|
||||
}).toWarnDev(["It looks like you're using the wrong act()"], {
|
||||
withoutStack: true,
|
||||
});
|
||||
}).toWarnDev(
|
||||
[
|
||||
'ReactDOM.render is no longer supported in React 18.',
|
||||
"It looks like you're using the wrong act()",
|
||||
],
|
||||
{
|
||||
withoutStack: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('warns when using the wrong act version - test + dom: updates', () => {
|
||||
|
||||
@@ -390,9 +390,8 @@ describe('InspectedElement', () => {
|
||||
});
|
||||
|
||||
const container = document.createElement('div');
|
||||
await utils.actAsync(() =>
|
||||
ReactDOM.render(<Target a={1} b="abc" />, container),
|
||||
);
|
||||
const root = ReactDOM.createRoot(container);
|
||||
await utils.actAsync(() => root.render(<Target a={1} b="abc" />));
|
||||
|
||||
expect(targetRenderCount).toBe(1);
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
|
||||
+8
-2
@@ -1154,9 +1154,15 @@ describe('ReactDOMFiber', () => {
|
||||
expect(ops).toEqual(['A']);
|
||||
|
||||
if (__DEV__) {
|
||||
// TODO: this warning shouldn't be firing in the first place if user didn't call it.
|
||||
const errorCalls = console.error.calls.count();
|
||||
for (let i = 0; i < errorCalls; i++) {
|
||||
expect(console.error.calls.argsFor(0)[0]).toMatch(
|
||||
'ReactDOM.render is no longer supported in React 18',
|
||||
);
|
||||
expect(console.error.calls.argsFor(1)[0]).toMatch(
|
||||
'ReactDOM.render is no longer supported in React 18',
|
||||
);
|
||||
// TODO: this warning shouldn't be firing in the first place if user didn't call it.
|
||||
for (let i = 2; i < errorCalls; i++) {
|
||||
expect(console.error.calls.argsFor(i)[0]).toMatch(
|
||||
'unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.',
|
||||
);
|
||||
|
||||
@@ -787,16 +787,22 @@ describe('ReactErrorBoundaries', () => {
|
||||
|
||||
it('logs a single error when using error boundary', () => {
|
||||
const container = document.createElement('div');
|
||||
expect(() =>
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<BrokenRender />
|
||||
</ErrorBoundary>,
|
||||
container,
|
||||
),
|
||||
).toErrorDev('The above error occurred in the <BrokenRender> component:', {
|
||||
logAllErrors: true,
|
||||
});
|
||||
spyOnDev(console, 'error');
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<BrokenRender />
|
||||
</ErrorBoundary>,
|
||||
container,
|
||||
);
|
||||
if (__DEV__) {
|
||||
expect(console.error).toHaveBeenCalledTimes(2);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'ReactDOM.render is no longer supported',
|
||||
);
|
||||
expect(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'The above error occurred in the <BrokenRender> component:',
|
||||
);
|
||||
}
|
||||
|
||||
expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
|
||||
expect(Scheduler).toHaveYielded([
|
||||
|
||||
@@ -43,6 +43,13 @@ describe('ReactErrorLoggingRecovery', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
console.error = error => {
|
||||
if (
|
||||
typeof error === 'string' &&
|
||||
error.includes('ReactDOM.render is no longer supported in React 18')
|
||||
) {
|
||||
// Ignore legacy root deprecation warning
|
||||
return;
|
||||
}
|
||||
throw new Error('Buggy console.error');
|
||||
};
|
||||
});
|
||||
|
||||
@@ -668,16 +668,22 @@ describe('ReactLegacyErrorBoundaries', () => {
|
||||
|
||||
it('logs a single error using both error boundaries', () => {
|
||||
const container = document.createElement('div');
|
||||
expect(() =>
|
||||
ReactDOM.render(
|
||||
<BothErrorBoundaries>
|
||||
<BrokenRender />
|
||||
</BothErrorBoundaries>,
|
||||
container,
|
||||
),
|
||||
).toErrorDev('The above error occurred in the <BrokenRender> component', {
|
||||
logAllErrors: true,
|
||||
});
|
||||
spyOnDev(console, 'error');
|
||||
ReactDOM.render(
|
||||
<BothErrorBoundaries>
|
||||
<BrokenRender />
|
||||
</BothErrorBoundaries>,
|
||||
container,
|
||||
);
|
||||
if (__DEV__) {
|
||||
expect(console.error).toHaveBeenCalledTimes(2);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'ReactDOM.render is no longer supported',
|
||||
);
|
||||
expect(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'The above error occurred in the <BrokenRender> component:',
|
||||
);
|
||||
}
|
||||
|
||||
expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
|
||||
expect(log).toEqual([
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
let ReactDOM = require('react-dom');
|
||||
|
||||
describe('ReactDOMRoot', () => {
|
||||
let container;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
container = document.createElement('div');
|
||||
ReactDOM = require('react-dom');
|
||||
});
|
||||
|
||||
test('deprecation warning for ReactDOM.render', () => {
|
||||
spyOnDev(console, 'error');
|
||||
|
||||
ReactDOM.render('Hi', container);
|
||||
expect(container.textContent).toEqual('Hi');
|
||||
if (__DEV__) {
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'ReactDOM.render is no longer supported',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('deprecation warning for ReactDOM.hydrate', () => {
|
||||
spyOnDev(console, 'error');
|
||||
|
||||
container.innerHTML = 'Hi';
|
||||
ReactDOM.hydrate('Hi', container);
|
||||
expect(container.textContent).toEqual('Hi');
|
||||
if (__DEV__) {
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'ReactDOM.hydrate is no longer supported',
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
+22
-15
@@ -10,6 +10,7 @@
|
||||
'use strict';
|
||||
|
||||
const stream = require('stream');
|
||||
const shouldIgnoreConsoleError = require('../../../../../scripts/jest/shouldIgnoreConsoleError');
|
||||
|
||||
module.exports = function(initModules) {
|
||||
let ReactDOM;
|
||||
@@ -74,23 +75,29 @@ module.exports = function(initModules) {
|
||||
}
|
||||
|
||||
const result = await fn();
|
||||
if (
|
||||
console.error.calls &&
|
||||
console.error.calls.count() !== count &&
|
||||
console.error.calls.count() !== 0
|
||||
) {
|
||||
console.log(
|
||||
`We expected ${count} warning(s), but saw ${console.error.calls.count()} warning(s).`,
|
||||
);
|
||||
if (console.error.calls.count() > 0) {
|
||||
console.log(`We saw these warnings:`);
|
||||
for (let i = 0; i < console.error.calls.count(); i++) {
|
||||
console.log(...console.error.calls.argsFor(i));
|
||||
if (console.error.calls && console.error.calls.count() !== 0) {
|
||||
const filteredWarnings = [];
|
||||
for (let i = 0; i < console.error.calls.count(); i++) {
|
||||
const args = console.error.calls.argsFor(i);
|
||||
const [format, ...rest] = args;
|
||||
if (!shouldIgnoreConsoleError(format, rest)) {
|
||||
filteredWarnings.push(args);
|
||||
}
|
||||
}
|
||||
if (filteredWarnings.length !== count) {
|
||||
console.log(
|
||||
`We expected ${count} warning(s), but saw ${filteredWarnings.length} warning(s).`,
|
||||
);
|
||||
if (filteredWarnings.count > 0) {
|
||||
console.log(`We saw these warnings:`);
|
||||
for (let i = 0; i < filteredWarnings.length; i++) {
|
||||
console.log(...filteredWarnings[i]);
|
||||
}
|
||||
}
|
||||
if (__DEV__) {
|
||||
expect(console.error).toHaveBeenCalledTimes(count);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (__DEV__) {
|
||||
expect(console.error).toHaveBeenCalledTimes(count);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+18
@@ -219,6 +219,15 @@ export function hydrate(
|
||||
container: Container,
|
||||
callback: ?Function,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
console.error(
|
||||
'ReactDOM.hydrate 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. Learn " +
|
||||
'more: https://reactjs.org/link/switch-to-createroot',
|
||||
);
|
||||
}
|
||||
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'Target container is not a DOM element.',
|
||||
@@ -250,6 +259,15 @@ export function render(
|
||||
container: Container,
|
||||
callback: ?Function,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
console.error(
|
||||
'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. Learn " +
|
||||
'more: https://reactjs.org/link/switch-to-createroot',
|
||||
);
|
||||
}
|
||||
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'Target container is not a DOM element.',
|
||||
|
||||
@@ -13,6 +13,16 @@ module.exports = function shouldIgnoreConsoleError(format, args) {
|
||||
// Ignore it too.
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
format.indexOf('ReactDOM.render is no longer supported in React 18') !==
|
||||
-1 ||
|
||||
format.indexOf(
|
||||
'ReactDOM.hydrate is no longer supported in React 18'
|
||||
) !== -1
|
||||
) {
|
||||
// We haven't finished migrating our tests to use createRoot.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user