Skip to content

Commit 5d85254

Browse files
committed
Add unsafe life-cycle warnings to partial renderer for parity
This aligns it with Fizz and how the client class components does it. It warns about using both, and not specifically about componentWillMount being renamed if both are used.
1 parent 99b7130 commit 5d85254

File tree

2 files changed

+102
-26
lines changed

2 files changed

+102
-26
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ describe('ReactDOMServerLifecycles', () => {
115115
}
116116
}
117117

118-
ReactDOMServer.renderToString(<Component />);
118+
expect(() => ReactDOMServer.renderToString(<Component />)).toErrorDev(
119+
'Unsafe legacy lifecycles will not be called for components using new component APIs.',
120+
);
119121
});
120122

121123
it('should update instance.state with value returned from getDerivedStateFromProps', () => {
@@ -279,8 +281,8 @@ describe('ReactDOMServerLifecycles', () => {
279281
}
280282
}
281283

282-
expect(() => ReactDOMServer.renderToString(<Component />)).toWarnDev(
283-
'componentWillMount has been renamed',
284+
expect(() => ReactDOMServer.renderToString(<Component />)).toErrorDev(
285+
'Unsafe legacy lifecycles will not be called for components using new component APIs.',
284286
);
285287
});
286288

packages/react-dom/src/server/ReactPartialRenderer.js

Lines changed: 97 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ const didWarnAboutModulePatternComponent = {};
194194
const didWarnAboutDeprecatedWillMount = {};
195195
const didWarnAboutUndefinedDerivedState = {};
196196
const didWarnAboutUninitializedState = {};
197+
const didWarnAboutLegacyLifecyclesAndDerivedState = {};
197198
const valuePropNames = ['value', 'defaultValue'];
198199
const newlineEatingTags = {
199200
listing: true,
@@ -475,6 +476,79 @@ function resolve(
475476
didWarnAboutUninitializedState[componentName] = true;
476477
}
477478
}
479+
480+
// If new component APIs are defined, "unsafe" lifecycles won't be called.
481+
// Warn about these lifecycles if they are present.
482+
// Don't warn about react-lifecycles-compat polyfilled methods though.
483+
if (
484+
typeof Component.getDerivedStateFromProps === 'function' ||
485+
typeof inst.getSnapshotBeforeUpdate === 'function'
486+
) {
487+
let foundWillMountName = null;
488+
let foundWillReceivePropsName = null;
489+
let foundWillUpdateName = null;
490+
if (
491+
typeof inst.componentWillMount === 'function' &&
492+
inst.componentWillMount.__suppressDeprecationWarning !== true
493+
) {
494+
foundWillMountName = 'componentWillMount';
495+
} else if (typeof inst.UNSAFE_componentWillMount === 'function') {
496+
foundWillMountName = 'UNSAFE_componentWillMount';
497+
}
498+
if (
499+
typeof inst.componentWillReceiveProps === 'function' &&
500+
inst.componentWillReceiveProps.__suppressDeprecationWarning !==
501+
true
502+
) {
503+
foundWillReceivePropsName = 'componentWillReceiveProps';
504+
} else if (
505+
typeof inst.UNSAFE_componentWillReceiveProps === 'function'
506+
) {
507+
foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps';
508+
}
509+
if (
510+
typeof inst.componentWillUpdate === 'function' &&
511+
inst.componentWillUpdate.__suppressDeprecationWarning !== true
512+
) {
513+
foundWillUpdateName = 'componentWillUpdate';
514+
} else if (typeof inst.UNSAFE_componentWillUpdate === 'function') {
515+
foundWillUpdateName = 'UNSAFE_componentWillUpdate';
516+
}
517+
if (
518+
foundWillMountName !== null ||
519+
foundWillReceivePropsName !== null ||
520+
foundWillUpdateName !== null
521+
) {
522+
const componentName =
523+
getComponentNameFromType(Component) || 'Component';
524+
const newApiName =
525+
typeof Component.getDerivedStateFromProps === 'function'
526+
? 'getDerivedStateFromProps()'
527+
: 'getSnapshotBeforeUpdate()';
528+
if (!didWarnAboutLegacyLifecyclesAndDerivedState[componentName]) {
529+
didWarnAboutLegacyLifecyclesAndDerivedState[
530+
componentName
531+
] = true;
532+
console.error(
533+
'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
534+
'%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n' +
535+
'The above lifecycles should be removed. Learn more about this warning here:\n' +
536+
'https://reactjs.org/link/unsafe-component-lifecycles',
537+
componentName,
538+
newApiName,
539+
foundWillMountName !== null
540+
? `\n ${foundWillMountName}`
541+
: '',
542+
foundWillReceivePropsName !== null
543+
? `\n ${foundWillReceivePropsName}`
544+
: '',
545+
foundWillUpdateName !== null
546+
? `\n ${foundWillUpdateName}`
547+
: '',
548+
);
549+
}
550+
}
551+
}
478552
}
479553

480554
const partialState = Component.getDerivedStateFromProps.call(
@@ -575,32 +649,32 @@ function resolve(
575649
typeof inst.componentWillMount === 'function'
576650
) {
577651
if (typeof inst.componentWillMount === 'function') {
578-
if (__DEV__) {
579-
if (
580-
warnAboutDeprecatedLifecycles &&
581-
inst.componentWillMount.__suppressDeprecationWarning !== true
582-
) {
583-
const componentName =
584-
getComponentNameFromType(Component) || 'Unknown';
585-
586-
if (!didWarnAboutDeprecatedWillMount[componentName]) {
587-
console.warn(
588-
// keep this warning in sync with ReactStrictModeWarning.js
589-
'componentWillMount has been renamed, and is not recommended for use. ' +
590-
'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' +
591-
'* Move code from componentWillMount to componentDidMount (preferred in most cases) ' +
592-
'or the constructor.\n' +
593-
'\nPlease update the following components: %s',
594-
componentName,
595-
);
596-
didWarnAboutDeprecatedWillMount[componentName] = true;
597-
}
598-
}
599-
}
600-
601652
// In order to support react-lifecycles-compat polyfilled components,
602653
// Unsafe lifecycles should not be invoked for any component with the new gDSFP.
603654
if (typeof Component.getDerivedStateFromProps !== 'function') {
655+
if (__DEV__) {
656+
if (
657+
warnAboutDeprecatedLifecycles &&
658+
inst.componentWillMount.__suppressDeprecationWarning !== true
659+
) {
660+
const componentName =
661+
getComponentNameFromType(Component) || 'Unknown';
662+
663+
if (!didWarnAboutDeprecatedWillMount[componentName]) {
664+
console.warn(
665+
// keep this warning in sync with ReactStrictModeWarning.js
666+
'componentWillMount has been renamed, and is not recommended for use. ' +
667+
'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' +
668+
'* Move code from componentWillMount to componentDidMount (preferred in most cases) ' +
669+
'or the constructor.\n' +
670+
'\nPlease update the following components: %s',
671+
componentName,
672+
);
673+
didWarnAboutDeprecatedWillMount[componentName] = true;
674+
}
675+
}
676+
}
677+
604678
inst.componentWillMount();
605679
}
606680
}

0 commit comments

Comments
 (0)