mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
Enabled warnAboutDeprecatedLifecycles flag by default (#15186)
This commit is contained in:
@@ -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(<MyComponent x={1} />, 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(<MyComponent x={2} />, container);
|
||||
ReactDOM.render(<MyComponent key="new" x={1} />, 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(
|
||||
<React.StrictMode>
|
||||
<PolyfilledComponent />
|
||||
</React.StrictMode>,
|
||||
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(
|
||||
<React.StrictMode>
|
||||
<PolyfilledComponent />
|
||||
</React.StrictMode>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -702,8 +702,17 @@ describe('ReactComponentLifeCycle', () => {
|
||||
}
|
||||
|
||||
const container = document.createElement('div');
|
||||
expect(() => ReactDOM.render(<Component />, container)).toWarnDev(
|
||||
'Unsafe legacy lifecycles will not be called for components using new component APIs.',
|
||||
expect(() => {
|
||||
expect(() => ReactDOM.render(<Component />, 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(<Component value={1} />, container)).toWarnDev(
|
||||
'Unsafe legacy lifecycles will not be called for components using new component APIs.',
|
||||
expect(() => {
|
||||
expect(() =>
|
||||
ReactDOM.render(<Component value={1} />, 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(<Component value={2} />, container);
|
||||
@@ -781,14 +801,21 @@ describe('ReactComponentLifeCycle', () => {
|
||||
}
|
||||
}
|
||||
|
||||
expect(() => ReactDOM.render(<AllLegacyLifecycles />, 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(<AllLegacyLifecycles />, 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(<WillMountAndUpdate />, 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(<WillMountAndUpdate />, 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(<WillReceiveProps />, 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(<WillReceiveProps />, 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(<AllLegacyLifecycles />, 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(<AllLegacyLifecycles />, 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(<WillMountAndUpdate />, 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(<WillMountAndUpdate />, 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(<WillReceiveProps />, 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(<WillReceiveProps />, 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(<MyComponent foo="bar" />, div);
|
||||
expect(() =>
|
||||
ReactDOM.render(<MyComponent foo="bar" />, 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(<MyComponent />, 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(<MyComponent x={1} />, 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(<MyComponent x={2} />, container);
|
||||
ReactDOM.render(<MyComponent key="new" x={1} />, 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(
|
||||
<React.StrictMode>
|
||||
<PolyfilledComponent />
|
||||
</React.StrictMode>,
|
||||
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(
|
||||
<React.StrictMode>
|
||||
<PolyfilledComponent />
|
||||
</React.StrictMode>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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(<Component />),
|
||||
).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(<Component />),
|
||||
).toLowPriorityWarnDev(
|
||||
'Warning: Component: componentWillMount() is deprecated and will be removed ' +
|
||||
'in the next major version.',
|
||||
{withoutStack: true},
|
||||
);
|
||||
|
||||
// De-duped
|
||||
ReactDOMServer.renderToString(<Component />);
|
||||
});
|
||||
|
||||
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(
|
||||
<React.StrictMode>
|
||||
<PolyfilledComponent />
|
||||
</React.StrictMode>,
|
||||
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(
|
||||
<React.StrictMode>
|
||||
<PolyfilledComponent />
|
||||
</React.StrictMode>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -227,7 +227,11 @@ describe('ReactDOMServerLifecycles', () => {
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOMServer.renderToString(<Component />);
|
||||
expect(() =>
|
||||
ReactDOMServer.renderToString(<Component />),
|
||||
).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(<Component />),
|
||||
).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(<Component />),
|
||||
).toLowPriorityWarnDev(
|
||||
'Warning: Component: componentWillMount() is deprecated and will be removed ' +
|
||||
'in the next major version.',
|
||||
{withoutStack: true},
|
||||
);
|
||||
|
||||
// De-duped
|
||||
ReactDOMServer.renderToString(<Component />);
|
||||
});
|
||||
|
||||
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(
|
||||
<React.StrictMode>
|
||||
<PolyfilledComponent />
|
||||
</React.StrictMode>,
|
||||
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(
|
||||
<React.StrictMode>
|
||||
<PolyfilledComponent />
|
||||
</React.StrictMode>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
@@ -411,20 +411,29 @@ describe('ReactStrictMode', () => {
|
||||
|
||||
let rendered;
|
||||
|
||||
expect(
|
||||
() => (rendered = ReactTestRenderer.create(<SyncRoot />)),
|
||||
).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(<SyncRoot />)),
|
||||
).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(<SyncRoot />)),
|
||||
).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(<SyncRoot />)),
|
||||
).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(<SyncRoot />);
|
||||
|
||||
@@ -9,119 +9,24 @@
|
||||
|
||||
'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 <div />;
|
||||
},
|
||||
});
|
||||
|
||||
const container = document.createElement('div');
|
||||
|
||||
expect(() => ReactDOM.render(<Component />, 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(<Component />, 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 React;
|
||||
let ReactNative;
|
||||
let NativeMethodsMixin;
|
||||
let createReactClass;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
React = require('react');
|
||||
|
||||
createReactClass = require('create-react-class/factory')(
|
||||
React.Component,
|
||||
React.isValidElement,
|
||||
new React.Component().updater,
|
||||
);
|
||||
|
||||
ReactNative = require('react-native-renderer');
|
||||
NativeMethodsMixin =
|
||||
ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
||||
|
||||
@@ -546,15 +546,24 @@ describe('create-react-class-integration', () => {
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
ReactDOM.render(<Component />, 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(<Component />, 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(<Component foo={1} />, document.createElement('div'));
|
||||
@@ -581,15 +590,24 @@ describe('create-react-class-integration', () => {
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
ReactDOM.render(<Component />, 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(<Component />, 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(<Component foo={1} />, document.createElement('div'));
|
||||
@@ -627,7 +645,16 @@ describe('create-react-class-integration', () => {
|
||||
});
|
||||
|
||||
const div = document.createElement('div');
|
||||
ReactDOM.render(<Component foo="bar" />, div);
|
||||
expect(() =>
|
||||
ReactDOM.render(<Component foo="bar" />, 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,89 @@ 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 <div />;
|
||||
},
|
||||
});
|
||||
|
||||
const container = document.createElement('div');
|
||||
|
||||
expect(() => ReactDOM.render(<Component />, 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(<Component />, 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',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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__;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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__;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user