diff --git a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.internal.js b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.internal.js
deleted file mode 100644
index ed65a16f0124e..0000000000000
--- a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.internal.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @emails react-core
- */
-
-'use strict';
-
-let React;
-let ReactDOM;
-let ReactFeatureFlags;
-
-describe('ReactComponentLifeCycle', () => {
- beforeEach(() => {
- jest.resetModules();
-
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
- ReactFeatureFlags.warnAboutDeprecatedLifecycles = true;
-
- React = require('react');
- ReactDOM = require('react-dom');
- });
-
- afterEach(() => {
- jest.resetModules();
- });
-
- // TODO (RFC #6) Merge this back into ReactComponentLifeCycles-test once
- // the 'warnAboutDeprecatedLifecycles' feature flag has been removed.
- it('warns about deprecated unsafe lifecycles', function() {
- class MyComponent extends React.Component {
- componentWillMount() {}
- componentWillReceiveProps() {}
- componentWillUpdate() {}
- render() {
- return null;
- }
- }
-
- const container = document.createElement('div');
- expect(() =>
- ReactDOM.render(, container),
- ).toLowPriorityWarnDev(
- [
- 'componentWillMount is deprecated and will be removed in the next major version. ' +
- 'Use componentDidMount instead. As a temporary workaround, ' +
- 'you can rename to UNSAFE_componentWillMount.' +
- '\n\nPlease update the following components: MyComponent',
- 'componentWillReceiveProps is deprecated and will be removed in the next major version. ' +
- 'Use static getDerivedStateFromProps instead.' +
- '\n\nPlease update the following components: MyComponent',
- 'componentWillUpdate is deprecated and will be removed in the next major version. ' +
- 'Use componentDidUpdate instead. As a temporary workaround, ' +
- 'you can rename to UNSAFE_componentWillUpdate.' +
- '\n\nPlease update the following components: MyComponent',
- ],
- {withoutStack: true},
- );
-
- // Dedupe check (update and instantiate new
- ReactDOM.render(, container);
- ReactDOM.render(, container);
- });
-
- describe('react-lifecycles-compat', () => {
- const {polyfill} = require('react-lifecycles-compat');
-
- it('should not warn for components with polyfilled getDerivedStateFromProps', () => {
- class PolyfilledComponent extends React.Component {
- state = {};
- static getDerivedStateFromProps() {
- return null;
- }
- render() {
- return null;
- }
- }
-
- polyfill(PolyfilledComponent);
-
- const container = document.createElement('div');
- ReactDOM.render(
-
-
- ,
- container,
- );
- });
-
- it('should not warn for components with polyfilled getSnapshotBeforeUpdate', () => {
- class PolyfilledComponent extends React.Component {
- getSnapshotBeforeUpdate() {
- return null;
- }
- componentDidUpdate() {}
- render() {
- return null;
- }
- }
-
- polyfill(PolyfilledComponent);
-
- const container = document.createElement('div');
- ReactDOM.render(
-
-
- ,
- container,
- );
- });
- });
-});
diff --git a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
index 05c70bac3ca96..fd286f1e68c8e 100644
--- a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
+++ b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
@@ -702,8 +702,17 @@ describe('ReactComponentLifeCycle', () => {
}
const container = document.createElement('div');
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.',
+ expect(() => {
+ expect(() => ReactDOM.render(, container)).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(
+ [
+ 'componentWillMount is deprecated',
+ 'componentWillReceiveProps is deprecated',
+ 'componentWillUpdate is deprecated',
+ ],
{withoutStack: true},
);
});
@@ -730,8 +739,19 @@ describe('ReactComponentLifeCycle', () => {
}
const container = document.createElement('div');
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.',
+ expect(() => {
+ expect(() =>
+ ReactDOM.render(, container),
+ ).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(
+ [
+ 'componentWillMount is deprecated',
+ 'componentWillReceiveProps is deprecated',
+ 'componentWillUpdate is deprecated',
+ ],
{withoutStack: true},
);
ReactDOM.render(, container);
@@ -781,14 +801,21 @@ describe('ReactComponentLifeCycle', () => {
}
}
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
- 'AllLegacyLifecycles uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
- ' componentWillMount\n' +
- ' UNSAFE_componentWillReceiveProps\n' +
- ' componentWillUpdate\n\n' +
- 'The above lifecycles should be removed. Learn more about this warning here:\n' +
- 'https://fb.me/react-async-component-lifecycle-hooks',
+ expect(() => {
+ expect(() =>
+ ReactDOM.render(, container),
+ ).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
+ 'AllLegacyLifecycles uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
+ ' componentWillMount\n' +
+ ' UNSAFE_componentWillReceiveProps\n' +
+ ' componentWillUpdate\n\n' +
+ 'The above lifecycles should be removed. Learn more about this warning here:\n' +
+ 'https://fb.me/react-async-component-lifecycle-hooks',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(
+ ['componentWillMount is deprecated', 'componentWillUpdate is deprecated'],
{withoutStack: true},
);
@@ -824,15 +851,21 @@ describe('ReactComponentLifeCycle', () => {
}
}
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
- 'WillMountAndUpdate uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
- ' componentWillMount\n' +
- ' UNSAFE_componentWillUpdate\n\n' +
- 'The above lifecycles should be removed. Learn more about this warning here:\n' +
- 'https://fb.me/react-async-component-lifecycle-hooks',
- {withoutStack: true},
- );
+ expect(() => {
+ expect(() =>
+ ReactDOM.render(, container),
+ ).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
+ 'WillMountAndUpdate uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
+ ' componentWillMount\n' +
+ ' UNSAFE_componentWillUpdate\n\n' +
+ 'The above lifecycles should be removed. Learn more about this warning here:\n' +
+ 'https://fb.me/react-async-component-lifecycle-hooks',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(['componentWillMount is deprecated'], {
+ withoutStack: true,
+ });
class WillReceiveProps extends React.Component {
state = {};
@@ -845,14 +878,18 @@ describe('ReactComponentLifeCycle', () => {
}
}
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
- 'WillReceiveProps uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
- ' componentWillReceiveProps\n\n' +
- 'The above lifecycles should be removed. Learn more about this warning here:\n' +
- 'https://fb.me/react-async-component-lifecycle-hooks',
- {withoutStack: true},
- );
+ expect(() => {
+ expect(() => ReactDOM.render(, container)).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
+ 'WillReceiveProps uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
+ ' componentWillReceiveProps\n\n' +
+ 'The above lifecycles should be removed. Learn more about this warning here:\n' +
+ 'https://fb.me/react-async-component-lifecycle-hooks',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(['componentWillReceiveProps is deprecated'], {
+ withoutStack: true,
+ });
});
it('should warn about deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', () => {
@@ -870,14 +907,21 @@ describe('ReactComponentLifeCycle', () => {
}
}
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
- 'AllLegacyLifecycles uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
- ' componentWillMount\n' +
- ' UNSAFE_componentWillReceiveProps\n' +
- ' componentWillUpdate\n\n' +
- 'The above lifecycles should be removed. Learn more about this warning here:\n' +
- 'https://fb.me/react-async-component-lifecycle-hooks',
+ expect(() => {
+ expect(() =>
+ ReactDOM.render(, container),
+ ).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
+ 'AllLegacyLifecycles uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
+ ' componentWillMount\n' +
+ ' UNSAFE_componentWillReceiveProps\n' +
+ ' componentWillUpdate\n\n' +
+ 'The above lifecycles should be removed. Learn more about this warning here:\n' +
+ 'https://fb.me/react-async-component-lifecycle-hooks',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(
+ ['componentWillMount is deprecated', 'componentWillUpdate is deprecated'],
{withoutStack: true},
);
@@ -911,15 +955,21 @@ describe('ReactComponentLifeCycle', () => {
}
}
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
- 'WillMountAndUpdate uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
- ' componentWillMount\n' +
- ' UNSAFE_componentWillUpdate\n\n' +
- 'The above lifecycles should be removed. Learn more about this warning here:\n' +
- 'https://fb.me/react-async-component-lifecycle-hooks',
- {withoutStack: true},
- );
+ expect(() => {
+ expect(() =>
+ ReactDOM.render(, container),
+ ).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
+ 'WillMountAndUpdate uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
+ ' componentWillMount\n' +
+ ' UNSAFE_componentWillUpdate\n\n' +
+ 'The above lifecycles should be removed. Learn more about this warning here:\n' +
+ 'https://fb.me/react-async-component-lifecycle-hooks',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(['componentWillMount is deprecated'], {
+ withoutStack: true,
+ });
class WillReceiveProps extends React.Component {
state = {};
@@ -931,14 +981,18 @@ describe('ReactComponentLifeCycle', () => {
}
}
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
- 'WillReceiveProps uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
- ' componentWillReceiveProps\n\n' +
- 'The above lifecycles should be removed. Learn more about this warning here:\n' +
- 'https://fb.me/react-async-component-lifecycle-hooks',
- {withoutStack: true},
- );
+ expect(() => {
+ expect(() => ReactDOM.render(, container)).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
+ 'WillReceiveProps uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
+ ' componentWillReceiveProps\n\n' +
+ 'The above lifecycles should be removed. Learn more about this warning here:\n' +
+ 'https://fb.me/react-async-component-lifecycle-hooks',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(['componentWillReceiveProps is deprecated'], {
+ withoutStack: true,
+ });
});
it('calls effects on module-pattern component', function() {
@@ -1072,7 +1126,16 @@ describe('ReactComponentLifeCycle', () => {
}
const div = document.createElement('div');
- ReactDOM.render(, div);
+ expect(() =>
+ ReactDOM.render(, div),
+ ).toLowPriorityWarnDev(
+ [
+ 'componentWillMount is deprecated',
+ 'componentWillReceiveProps is deprecated',
+ 'componentWillUpdate is deprecated',
+ ],
+ {withoutStack: true},
+ );
expect(log).toEqual(['componentWillMount', 'UNSAFE_componentWillMount']);
log.length = 0;
@@ -1324,4 +1387,87 @@ describe('ReactComponentLifeCycle', () => {
// De-duped
ReactDOM.render(, div);
});
+
+ it('warns about deprecated unsafe lifecycles', function() {
+ class MyComponent extends React.Component {
+ componentWillMount() {}
+ componentWillReceiveProps() {}
+ componentWillUpdate() {}
+ render() {
+ return null;
+ }
+ }
+
+ const container = document.createElement('div');
+ expect(() =>
+ ReactDOM.render(, container),
+ ).toLowPriorityWarnDev(
+ [
+ 'componentWillMount is deprecated and will be removed in the next major version. ' +
+ 'Use componentDidMount instead. As a temporary workaround, ' +
+ 'you can rename to UNSAFE_componentWillMount.' +
+ '\n\nPlease update the following components: MyComponent',
+ 'componentWillReceiveProps is deprecated and will be removed in the next major version. ' +
+ 'Use static getDerivedStateFromProps instead.' +
+ '\n\nPlease update the following components: MyComponent',
+ 'componentWillUpdate is deprecated and will be removed in the next major version. ' +
+ 'Use componentDidUpdate instead. As a temporary workaround, ' +
+ 'you can rename to UNSAFE_componentWillUpdate.' +
+ '\n\nPlease update the following components: MyComponent',
+ ],
+ {withoutStack: true},
+ );
+
+ // Dedupe check (update and instantiate new
+ ReactDOM.render(, container);
+ ReactDOM.render(, container);
+ });
+
+ describe('react-lifecycles-compat', () => {
+ const {polyfill} = require('react-lifecycles-compat');
+
+ it('should not warn for components with polyfilled getDerivedStateFromProps', () => {
+ class PolyfilledComponent extends React.Component {
+ state = {};
+ static getDerivedStateFromProps() {
+ return null;
+ }
+ render() {
+ return null;
+ }
+ }
+
+ polyfill(PolyfilledComponent);
+
+ const container = document.createElement('div');
+ ReactDOM.render(
+
+
+ ,
+ container,
+ );
+ });
+
+ it('should not warn for components with polyfilled getSnapshotBeforeUpdate', () => {
+ class PolyfilledComponent extends React.Component {
+ getSnapshotBeforeUpdate() {
+ return null;
+ }
+ componentDidUpdate() {}
+ render() {
+ return null;
+ }
+ }
+
+ polyfill(PolyfilledComponent);
+
+ const container = document.createElement('div');
+ ReactDOM.render(
+
+
+ ,
+ container,
+ );
+ });
+ });
});
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.internal.js
deleted file mode 100644
index 0e3f2a70ff69f..0000000000000
--- a/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.internal.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @emails react-core
- */
-
-'use strict';
-
-let React;
-let ReactFeatureFlags;
-let ReactDOMServer;
-
-describe('ReactDOMServerLifecycles', () => {
- beforeEach(() => {
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
- ReactFeatureFlags.warnAboutDeprecatedLifecycles = true;
-
- React = require('react');
- ReactDOMServer = require('react-dom/server');
- });
-
- afterEach(() => {
- jest.resetModules();
- });
-
- it('should not invoke cWM if static gDSFP is present', () => {
- class Component extends React.Component {
- state = {};
- static getDerivedStateFromProps() {
- return null;
- }
- componentWillMount() {
- throw Error('unexpected');
- }
- render() {
- return null;
- }
- }
-
- expect(() =>
- ReactDOMServer.renderToString(),
- ).toLowPriorityWarnDev(
- 'Component: componentWillMount() is deprecated and will be removed in the next major version.',
- {withoutStack: true},
- );
- });
-
- // TODO (RFC #6) Merge this back into ReactDOMServerLifecycles-test once
- // the 'warnAboutDeprecatedLifecycles' feature flag has been removed.
- it('should warn about deprecated lifecycle hooks', () => {
- class Component extends React.Component {
- componentWillMount() {}
- render() {
- return null;
- }
- }
-
- expect(() =>
- ReactDOMServer.renderToString(),
- ).toLowPriorityWarnDev(
- 'Warning: Component: componentWillMount() is deprecated and will be removed ' +
- 'in the next major version.',
- {withoutStack: true},
- );
-
- // De-duped
- ReactDOMServer.renderToString();
- });
-
- describe('react-lifecycles-compat', () => {
- const {polyfill} = require('react-lifecycles-compat');
-
- it('should not warn for components with polyfilled getDerivedStateFromProps', () => {
- class PolyfilledComponent extends React.Component {
- state = {};
- static getDerivedStateFromProps() {
- return null;
- }
- render() {
- return null;
- }
- }
-
- polyfill(PolyfilledComponent);
-
- const container = document.createElement('div');
- ReactDOMServer.renderToString(
-
-
- ,
- container,
- );
- });
-
- it('should not warn for components with polyfilled getSnapshotBeforeUpdate', () => {
- class PolyfilledComponent extends React.Component {
- getSnapshotBeforeUpdate() {
- return null;
- }
- componentDidUpdate() {}
- render() {
- return null;
- }
- }
-
- polyfill(PolyfilledComponent);
-
- const container = document.createElement('div');
- ReactDOMServer.renderToString(
-
-
- ,
- container,
- );
- });
- });
-});
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js b/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js
index ad748e84e3b2c..76230a3230350 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js
@@ -227,7 +227,11 @@ describe('ReactDOMServerLifecycles', () => {
}
}
- ReactDOMServer.renderToString();
+ expect(() =>
+ ReactDOMServer.renderToString(),
+ ).toLowPriorityWarnDev('componentWillMount() is deprecated', {
+ withoutStack: true,
+ });
expect(log).toEqual(['componentWillMount', 'UNSAFE_componentWillMount']);
});
@@ -265,4 +269,94 @@ describe('ReactDOMServerLifecycles', () => {
{withoutStack: true},
);
});
+
+ it('should not invoke cWM if static gDSFP is present', () => {
+ class Component extends React.Component {
+ state = {};
+ static getDerivedStateFromProps() {
+ return null;
+ }
+ componentWillMount() {
+ throw Error('unexpected');
+ }
+ render() {
+ return null;
+ }
+ }
+
+ expect(() =>
+ ReactDOMServer.renderToString(),
+ ).toLowPriorityWarnDev(
+ 'Component: componentWillMount() is deprecated and will be removed in the next major version.',
+ {withoutStack: true},
+ );
+ });
+
+ it('should warn about deprecated lifecycle hooks', () => {
+ class Component extends React.Component {
+ componentWillMount() {}
+ render() {
+ return null;
+ }
+ }
+
+ expect(() =>
+ ReactDOMServer.renderToString(),
+ ).toLowPriorityWarnDev(
+ 'Warning: Component: componentWillMount() is deprecated and will be removed ' +
+ 'in the next major version.',
+ {withoutStack: true},
+ );
+
+ // De-duped
+ ReactDOMServer.renderToString();
+ });
+
+ describe('react-lifecycles-compat', () => {
+ const {polyfill} = require('react-lifecycles-compat');
+
+ it('should not warn for components with polyfilled getDerivedStateFromProps', () => {
+ class PolyfilledComponent extends React.Component {
+ state = {};
+ static getDerivedStateFromProps() {
+ return null;
+ }
+ render() {
+ return null;
+ }
+ }
+
+ polyfill(PolyfilledComponent);
+
+ const container = document.createElement('div');
+ ReactDOMServer.renderToString(
+
+
+ ,
+ container,
+ );
+ });
+
+ it('should not warn for components with polyfilled getSnapshotBeforeUpdate', () => {
+ class PolyfilledComponent extends React.Component {
+ getSnapshotBeforeUpdate() {
+ return null;
+ }
+ componentDidUpdate() {}
+ render() {
+ return null;
+ }
+ }
+
+ polyfill(PolyfilledComponent);
+
+ const container = document.createElement('div');
+ ReactDOMServer.renderToString(
+
+
+ ,
+ container,
+ );
+ });
+ });
});
diff --git a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
index c135cb221a860..e28183e1b3231 100644
--- a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
+++ b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
@@ -358,11 +358,21 @@ describe('ReactDOMServerHydration', () => {
);
const element = document.createElement('div');
- element.innerHTML = ReactDOMServer.renderToString(markup);
+ expect(() => {
+ element.innerHTML = ReactDOMServer.renderToString(markup);
+ }).toLowPriorityWarnDev(
+ ['componentWillMount() is deprecated and will be removed'],
+ {withoutStack: true},
+ );
expect(element.textContent).toBe('Hi');
- expect(() => ReactDOM.hydrate(markup, element)).toWarnDev(
- 'Please update the following components to use componentDidMount instead: ComponentWithWarning',
+ expect(() => {
+ expect(() => ReactDOM.hydrate(markup, element)).toWarnDev(
+ 'Please update the following components to use componentDidMount instead: ComponentWithWarning',
+ );
+ }).toLowPriorityWarnDev(
+ ['componentWillMount is deprecated and will be removed'],
+ {withoutStack: true},
);
expect(element.textContent).toBe('Hi');
});
diff --git a/packages/react/src/__tests__/ReactStrictMode-test.internal.js b/packages/react/src/__tests__/ReactStrictMode-test.internal.js
index 7c0b308e67cc3..14b33ce991805 100644
--- a/packages/react/src/__tests__/ReactStrictMode-test.internal.js
+++ b/packages/react/src/__tests__/ReactStrictMode-test.internal.js
@@ -411,20 +411,29 @@ describe('ReactStrictMode', () => {
let rendered;
- expect(
- () => (rendered = ReactTestRenderer.create()),
- ).toWarnDev(
- 'Unsafe lifecycle methods were found within a strict-mode tree:' +
- '\n in ConcurrentMode (at **)' +
- '\n in SyncRoot (at **)' +
- '\n\ncomponentWillMount: Please update the following components ' +
- 'to use componentDidMount instead: AsyncRoot, Parent' +
- '\n\ncomponentWillReceiveProps: Please update the following components ' +
- 'to use static getDerivedStateFromProps instead: Child, Parent' +
- '\n\ncomponentWillUpdate: Please update the following components ' +
- 'to use componentDidUpdate instead: AsyncRoot, Parent' +
- '\n\nLearn more about this warning here:' +
- '\nhttps://fb.me/react-strict-mode-warnings',
+ expect(() => {
+ expect(
+ () => (rendered = ReactTestRenderer.create()),
+ ).toWarnDev(
+ 'Unsafe lifecycle methods were found within a strict-mode tree:' +
+ '\n in ConcurrentMode (at **)' +
+ '\n in SyncRoot (at **)' +
+ '\n\ncomponentWillMount: Please update the following components ' +
+ 'to use componentDidMount instead: AsyncRoot, Parent' +
+ '\n\ncomponentWillReceiveProps: Please update the following components ' +
+ 'to use static getDerivedStateFromProps instead: Child, Parent' +
+ '\n\ncomponentWillUpdate: Please update the following components ' +
+ 'to use componentDidUpdate instead: AsyncRoot, Parent' +
+ '\n\nLearn more about this warning here:' +
+ '\nhttps://fb.me/react-strict-mode-warnings',
+ );
+ }).toLowPriorityWarnDev(
+ [
+ 'componentWillMount is deprecated',
+ 'componentWillReceiveProps is deprecated',
+ 'componentWillUpdate is deprecated',
+ ],
+ {withoutStack: true},
);
// Dedupe
@@ -489,24 +498,28 @@ describe('ReactStrictMode', () => {
let rendered;
- expect(
- () => (rendered = ReactTestRenderer.create()),
- ).toWarnDev([
- 'Unsafe lifecycle methods were found within a strict-mode tree:' +
- '\n in ConcurrentMode (at **)' +
- '\n in AsyncRootOne (at **)' +
- '\n in div (at **)' +
- '\n in SyncRoot (at **)' +
- '\n\ncomponentWillMount: Please update the following components ' +
- 'to use componentDidMount instead: Bar, Foo',
- 'Unsafe lifecycle methods were found within a strict-mode tree:' +
- '\n in ConcurrentMode (at **)' +
- '\n in AsyncRootTwo (at **)' +
- '\n in div (at **)' +
- '\n in SyncRoot (at **)' +
- '\n\ncomponentWillMount: Please update the following components ' +
- 'to use componentDidMount instead: Baz',
- ]);
+ expect(() => {
+ expect(
+ () => (rendered = ReactTestRenderer.create()),
+ ).toWarnDev([
+ 'Unsafe lifecycle methods were found within a strict-mode tree:' +
+ '\n in ConcurrentMode (at **)' +
+ '\n in AsyncRootOne (at **)' +
+ '\n in div (at **)' +
+ '\n in SyncRoot (at **)' +
+ '\n\ncomponentWillMount: Please update the following components ' +
+ 'to use componentDidMount instead: Bar, Foo',
+ 'Unsafe lifecycle methods were found within a strict-mode tree:' +
+ '\n in ConcurrentMode (at **)' +
+ '\n in AsyncRootTwo (at **)' +
+ '\n in div (at **)' +
+ '\n in SyncRoot (at **)' +
+ '\n\ncomponentWillMount: Please update the following components ' +
+ 'to use componentDidMount instead: Baz',
+ ]);
+ }).toLowPriorityWarnDev(['componentWillMount is deprecated'], {
+ withoutStack: true,
+ });
// Dedupe
rendered = ReactTestRenderer.create();
diff --git a/packages/react/src/__tests__/createReactClassIntegration-test.internal.js b/packages/react/src/__tests__/createReactClassIntegration-test.internal.js
deleted file mode 100644
index 16c10c370add1..0000000000000
--- a/packages/react/src/__tests__/createReactClassIntegration-test.internal.js
+++ /dev/null
@@ -1,173 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @emails react-core
- */
-
-'use strict';
-
-let React;
-let ReactFeatureFlags;
-let createReactClass;
-
-describe('create-react-class-integration', () => {
- beforeEach(() => {
- jest.resetModules();
-
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
- ReactFeatureFlags.warnAboutDeprecatedLifecycles = true;
-
- React = require('react');
- createReactClass = require('create-react-class/factory')(
- React.Component,
- React.isValidElement,
- new React.Component().updater,
- );
- });
-
- // TODO (RFC #6) Merge this back into createReactClassIntegration-test once
- // the 'warnAboutDeprecatedLifecycles' feature flag has been removed.
- it('isMounted works', () => {
- const ReactDOM = require('react-dom');
-
- const ops = [];
- let instance;
- const Component = createReactClass({
- displayName: 'MyComponent',
- mixins: [
- {
- UNSAFE_componentWillMount() {
- this.log('mixin.componentWillMount');
- },
- componentDidMount() {
- this.log('mixin.componentDidMount');
- },
- UNSAFE_componentWillUpdate() {
- this.log('mixin.componentWillUpdate');
- },
- componentDidUpdate() {
- this.log('mixin.componentDidUpdate');
- },
- componentWillUnmount() {
- this.log('mixin.componentWillUnmount');
- },
- },
- ],
- log(name) {
- ops.push(`${name}: ${this.isMounted()}`);
- },
- getInitialState() {
- this.log('getInitialState');
- return {};
- },
- UNSAFE_componentWillMount() {
- this.log('componentWillMount');
- },
- componentDidMount() {
- this.log('componentDidMount');
- },
- UNSAFE_componentWillUpdate() {
- this.log('componentWillUpdate');
- },
- componentDidUpdate() {
- this.log('componentDidUpdate');
- },
- componentWillUnmount() {
- this.log('componentWillUnmount');
- },
- render() {
- instance = this;
- this.log('render');
- return
;
- },
- });
-
- const container = document.createElement('div');
-
- expect(() => ReactDOM.render(, container)).toWarnDev(
- 'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
- 'clean up subscriptions and pending requests in componentWillUnmount ' +
- 'to prevent memory leaks.',
- {withoutStack: true},
- );
-
- // Dedupe
- ReactDOM.render(, container);
-
- ReactDOM.unmountComponentAtNode(container);
- instance.log('after unmount');
- expect(ops).toEqual([
- 'getInitialState: false',
- 'mixin.componentWillMount: false',
- 'componentWillMount: false',
- 'render: false',
- 'mixin.componentDidMount: true',
- 'componentDidMount: true',
- 'mixin.componentWillUpdate: true',
- 'componentWillUpdate: true',
- 'render: true',
- 'mixin.componentDidUpdate: true',
- 'componentDidUpdate: true',
- 'mixin.componentWillUnmount: true',
- 'componentWillUnmount: true',
- 'after unmount: false',
- ]);
- });
-
- describe('ReactNative NativeMethodsMixin', () => {
- let ReactNative;
- let NativeMethodsMixin;
-
- beforeEach(() => {
- ReactNative = require('react-native-renderer');
- NativeMethodsMixin =
- ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
- .NativeMethodsMixin;
- });
-
- it('should not warn about default DEV-only legacy lifecycle methods', () => {
- const View = createReactClass({
- mixins: [NativeMethodsMixin],
- render: () => null,
- });
-
- ReactNative.render(, 1);
- });
-
- it('should warn if users specify their own legacy componentWillMount', () => {
- const View = createReactClass({
- displayName: 'MyNativeComponent',
- mixins: [NativeMethodsMixin],
- componentWillMount: () => {},
- render: () => null,
- });
-
- expect(() => ReactNative.render(, 1)).toLowPriorityWarnDev(
- 'componentWillMount is deprecated and will be removed in the next major version. ' +
- 'Use componentDidMount instead. As a temporary workaround, ' +
- 'you can rename to UNSAFE_componentWillMount.' +
- '\n\nPlease update the following components: MyNativeComponent',
- {withoutStack: true},
- );
- });
-
- it('should warn if users specify their own legacy componentWillReceiveProps', () => {
- const View = createReactClass({
- displayName: 'MyNativeComponent',
- mixins: [NativeMethodsMixin],
- componentWillReceiveProps: () => {},
- render: () => null,
- });
-
- expect(() => ReactNative.render(, 1)).toLowPriorityWarnDev(
- 'componentWillReceiveProps is deprecated and will be removed in the next major version. ' +
- 'Use static getDerivedStateFromProps instead.' +
- '\n\nPlease update the following components: MyNativeComponent',
- {withoutStack: true},
- );
- });
- });
-});
diff --git a/packages/react/src/__tests__/createReactClassIntegration-test.js b/packages/react/src/__tests__/createReactClassIntegration-test.js
index efc2bf3ba49dc..c6e2315690d71 100644
--- a/packages/react/src/__tests__/createReactClassIntegration-test.js
+++ b/packages/react/src/__tests__/createReactClassIntegration-test.js
@@ -546,15 +546,24 @@ describe('create-react-class-integration', () => {
});
expect(() => {
- ReactDOM.render(, document.createElement('div'));
- }).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
- 'Component uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
- ' componentWillMount\n' +
- ' componentWillReceiveProps\n' +
- ' componentWillUpdate\n\n' +
- 'The above lifecycles should be removed. Learn more about this warning here:\n' +
- 'https://fb.me/react-async-component-lifecycle-hooks',
+ expect(() => {
+ ReactDOM.render(, document.createElement('div'));
+ }).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
+ 'Component uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
+ ' componentWillMount\n' +
+ ' componentWillReceiveProps\n' +
+ ' componentWillUpdate\n\n' +
+ 'The above lifecycles should be removed. Learn more about this warning here:\n' +
+ 'https://fb.me/react-async-component-lifecycle-hooks',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(
+ [
+ 'componentWillMount is deprecated',
+ 'componentWillReceiveProps is deprecated',
+ 'componentWillUpdate is deprecated',
+ ],
{withoutStack: true},
);
ReactDOM.render(, document.createElement('div'));
@@ -581,15 +590,24 @@ describe('create-react-class-integration', () => {
});
expect(() => {
- ReactDOM.render(, document.createElement('div'));
- }).toWarnDev(
- 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
- 'Component uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
- ' componentWillMount\n' +
- ' componentWillReceiveProps\n' +
- ' componentWillUpdate\n\n' +
- 'The above lifecycles should be removed. Learn more about this warning here:\n' +
- 'https://fb.me/react-async-component-lifecycle-hooks',
+ expect(() => {
+ ReactDOM.render(, document.createElement('div'));
+ }).toWarnDev(
+ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
+ 'Component uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
+ ' componentWillMount\n' +
+ ' componentWillReceiveProps\n' +
+ ' componentWillUpdate\n\n' +
+ 'The above lifecycles should be removed. Learn more about this warning here:\n' +
+ 'https://fb.me/react-async-component-lifecycle-hooks',
+ {withoutStack: true},
+ );
+ }).toLowPriorityWarnDev(
+ [
+ 'componentWillMount is deprecated',
+ 'componentWillReceiveProps is deprecated',
+ 'componentWillUpdate is deprecated',
+ ],
{withoutStack: true},
);
ReactDOM.render(, document.createElement('div'));
@@ -627,7 +645,16 @@ describe('create-react-class-integration', () => {
});
const div = document.createElement('div');
- ReactDOM.render(, div);
+ expect(() =>
+ ReactDOM.render(, div),
+ ).toLowPriorityWarnDev(
+ [
+ 'componentWillMount is deprecated',
+ 'componentWillReceiveProps is deprecated',
+ 'componentWillUpdate is deprecated',
+ ],
+ {withoutStack: true},
+ );
expect(log).toEqual(['componentWillMount', 'UNSAFE_componentWillMount']);
log.length = 0;
@@ -640,4 +667,145 @@ describe('create-react-class-integration', () => {
'UNSAFE_componentWillUpdate',
]);
});
+
+ it('isMounted works', () => {
+ const ops = [];
+ let instance;
+ const Component = createReactClass({
+ displayName: 'MyComponent',
+ mixins: [
+ {
+ UNSAFE_componentWillMount() {
+ this.log('mixin.componentWillMount');
+ },
+ componentDidMount() {
+ this.log('mixin.componentDidMount');
+ },
+ UNSAFE_componentWillUpdate() {
+ this.log('mixin.componentWillUpdate');
+ },
+ componentDidUpdate() {
+ this.log('mixin.componentDidUpdate');
+ },
+ componentWillUnmount() {
+ this.log('mixin.componentWillUnmount');
+ },
+ },
+ ],
+ log(name) {
+ ops.push(`${name}: ${this.isMounted()}`);
+ },
+ getInitialState() {
+ this.log('getInitialState');
+ return {};
+ },
+ UNSAFE_componentWillMount() {
+ this.log('componentWillMount');
+ },
+ componentDidMount() {
+ this.log('componentDidMount');
+ },
+ UNSAFE_componentWillUpdate() {
+ this.log('componentWillUpdate');
+ },
+ componentDidUpdate() {
+ this.log('componentDidUpdate');
+ },
+ componentWillUnmount() {
+ this.log('componentWillUnmount');
+ },
+ render() {
+ instance = this;
+ this.log('render');
+ return ;
+ },
+ });
+
+ const container = document.createElement('div');
+
+ expect(() => ReactDOM.render(, container)).toWarnDev(
+ 'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
+ 'clean up subscriptions and pending requests in componentWillUnmount ' +
+ 'to prevent memory leaks.',
+ {withoutStack: true},
+ );
+
+ // Dedupe
+ ReactDOM.render(, container);
+
+ ReactDOM.unmountComponentAtNode(container);
+ instance.log('after unmount');
+ expect(ops).toEqual([
+ 'getInitialState: false',
+ 'mixin.componentWillMount: false',
+ 'componentWillMount: false',
+ 'render: false',
+ 'mixin.componentDidMount: true',
+ 'componentDidMount: true',
+ 'mixin.componentWillUpdate: true',
+ 'componentWillUpdate: true',
+ 'render: true',
+ 'mixin.componentDidUpdate: true',
+ 'componentDidUpdate: true',
+ 'mixin.componentWillUnmount: true',
+ 'componentWillUnmount: true',
+ 'after unmount: false',
+ ]);
+ });
+
+ describe('ReactNative NativeMethodsMixin', () => {
+ let ReactNative;
+ let NativeMethodsMixin;
+
+ beforeEach(() => {
+ jest.resetModules();
+
+ ReactNative = require('react-native-renderer');
+ NativeMethodsMixin =
+ ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
+ .NativeMethodsMixin;
+ });
+
+ it('should not warn about default DEV-only legacy lifecycle methods', () => {
+ const View = createReactClass({
+ mixins: [NativeMethodsMixin],
+ render: () => null,
+ });
+
+ ReactNative.render(, 1);
+ });
+
+ it('should warn if users specify their own legacy componentWillMount', () => {
+ const View = createReactClass({
+ displayName: 'MyNativeComponent',
+ mixins: [NativeMethodsMixin],
+ componentWillMount: () => {},
+ render: () => null,
+ });
+
+ expect(() => ReactNative.render(, 1)).toLowPriorityWarnDev(
+ 'componentWillMount is deprecated and will be removed in the next major version. ' +
+ 'Use componentDidMount instead. As a temporary workaround, ' +
+ 'you can rename to UNSAFE_componentWillMount.' +
+ '\n\nPlease update the following components: MyNativeComponent',
+ {withoutStack: true},
+ );
+ });
+
+ it('should warn if users specify their own legacy componentWillReceiveProps', () => {
+ const View = createReactClass({
+ displayName: 'MyNativeComponent',
+ mixins: [NativeMethodsMixin],
+ componentWillReceiveProps: () => {},
+ render: () => null,
+ });
+
+ expect(() => ReactNative.render(, 1)).toLowPriorityWarnDev(
+ 'componentWillReceiveProps is deprecated and will be removed in the next major version. ' +
+ 'Use static getDerivedStateFromProps instead.' +
+ '\n\nPlease update the following components: MyNativeComponent',
+ {withoutStack: true},
+ );
+ });
+ });
});
diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js
index 9ace0090d6ca7..990dedf247649 100644
--- a/packages/shared/ReactFeatureFlags.js
+++ b/packages/shared/ReactFeatureFlags.js
@@ -23,7 +23,7 @@ export const debugRenderPhaseSideEffectsForStrictMode = __DEV__;
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
// Warn about deprecated, async-unsafe lifecycles; relates to RFC #6:
-export const warnAboutDeprecatedLifecycles = false;
+export const warnAboutDeprecatedLifecycles = true;
// Gather advanced timing metrics for Profiler subtrees.
export const enableProfilerTimer = __PROFILE__;
diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js
index e264fd3a34419..38e036682caac 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-oss.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js
@@ -16,7 +16,7 @@ export const debugRenderPhaseSideEffects = false;
export const debugRenderPhaseSideEffectsForStrictMode = false;
export const enableUserTimingAPI = __DEV__;
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
-export const warnAboutDeprecatedLifecycles = false;
+export const warnAboutDeprecatedLifecycles = true;
export const enableProfilerTimer = __PROFILE__;
export const enableSchedulerTracing = __PROFILE__;
export const enableSuspenseServerRenderer = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.persistent.js b/packages/shared/forks/ReactFeatureFlags.persistent.js
index 2b048a082236f..e5dc81c58b32d 100644
--- a/packages/shared/forks/ReactFeatureFlags.persistent.js
+++ b/packages/shared/forks/ReactFeatureFlags.persistent.js
@@ -15,7 +15,7 @@ import typeof * as PersistentFeatureFlagsType from './ReactFeatureFlags.persiste
export const debugRenderPhaseSideEffects = false;
export const debugRenderPhaseSideEffectsForStrictMode = false;
export const enableUserTimingAPI = __DEV__;
-export const warnAboutDeprecatedLifecycles = false;
+export const warnAboutDeprecatedLifecycles = true;
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
export const enableProfilerTimer = __PROFILE__;
export const enableSchedulerTracing = __PROFILE__;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
index 4b5df2e904080..97fc3164eb68c 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
@@ -15,7 +15,7 @@ import typeof * as PersistentFeatureFlagsType from './ReactFeatureFlags.persiste
export const debugRenderPhaseSideEffects = false;
export const debugRenderPhaseSideEffectsForStrictMode = false;
export const enableUserTimingAPI = __DEV__;
-export const warnAboutDeprecatedLifecycles = false;
+export const warnAboutDeprecatedLifecycles = true;
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
export const enableProfilerTimer = false;
export const enableSchedulerTracing = false;