Enabled warnAboutDeprecatedLifecycles flag by default (#15186)

This commit is contained in:
Brian Vaughn
2019-03-27 16:30:49 -07:00
committed by GitHub
parent 80f8b0d512
commit d8cb10f11f
12 changed files with 501 additions and 456 deletions

View File

@@ -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,
);
});
});
});

View File

@@ -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,
);
});
});
});

View File

@@ -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,
);
});
});
});

View File

@@ -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,
);
});
});
});

View File

@@ -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');
});

View File

@@ -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 />);

View File

@@ -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

View File

@@ -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',
]);
});
});

View File

@@ -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__;

View File

@@ -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;

View File

@@ -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__;

View File

@@ -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;