add warning when owner and self are different for string refs (#17864)

When owner and self are different for string refs, we can't easily convert them to callback refs. This PR adds a warning for string refs when owner and self are different to tell users to manually update these refs.
This commit is contained in:
Luna Ruan
2020-01-22 12:32:51 -08:00
committed by GitHub
parent 6c00c5bba4
commit 3b3decf871
3 changed files with 91 additions and 2 deletions
@@ -69,4 +69,44 @@ describe('ReactDeprecationWarnings', () => {
'\n in Component (at **)',
);
});
it('should not warn when owner and self are the same for string refs', () => {
ReactFeatureFlags.warnAboutStringRefs = false;
class RefComponent extends React.Component {
render() {
return null;
}
}
class Component extends React.Component {
render() {
return <RefComponent ref="refComponent" __self={this} />;
}
}
ReactNoop.renderLegacySyncRoot(<Component />);
expect(Scheduler).toFlushWithoutYielding();
});
it('should warn when owner and self are different for string refs', () => {
class RefComponent extends React.Component {
render() {
return null;
}
}
class Component extends React.Component {
render() {
return <RefComponent ref="refComponent" __self={{}} />;
}
}
ReactNoop.render(<Component />);
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([
'Warning: Component "Component" contains the string ref "refComponent". ' +
'Support for string refs will be removed in a future major release. ' +
'This case cannot be automatically converted to an arrow function. ' +
'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
'Learn more about using refs safely here: ' +
'https://fb.me/react-strict-mode-string-ref',
]);
});
});
+11 -1
View File
@@ -116,7 +116,17 @@ function coerceRef(
if (__DEV__) {
// TODO: Clean this up once we turn on the string ref warning for
// everyone, because the strict mode case will no longer be relevant
if (returnFiber.mode & StrictMode || warnAboutStringRefs) {
if (
(returnFiber.mode & StrictMode || warnAboutStringRefs) &&
// We warn in ReactElement.js if owner and self are equal for string refs
// because these cannot be automatically converted to an arrow function
// using a codemod. Therefore, we don't have to warn about string refs again.
!(
element._owner &&
element._self &&
element._owner.stateNode !== element._self
)
) {
const componentName = getComponentName(returnFiber.type) || 'Component';
if (!didWarnAboutStringRefs[componentName]) {
if (warnAboutStringRefs) {
+40 -1
View File
@@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import getComponentName from 'shared/getComponentName';
import invariant from 'shared/invariant';
import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
@@ -19,7 +20,13 @@ const RESERVED_PROPS = {
__source: true,
};
let specialPropKeyWarningShown, specialPropRefWarningShown;
let specialPropKeyWarningShown,
specialPropRefWarningShown,
didWarnAboutStringRefs;
if (__DEV__) {
didWarnAboutStringRefs = {};
}
function hasValidRef(config) {
if (__DEV__) {
@@ -89,6 +96,33 @@ function defineRefPropWarningGetter(props, displayName) {
});
}
function warnIfStringRefCannotBeAutoConverted(config) {
if (__DEV__) {
if (
typeof config.ref === 'string' &&
ReactCurrentOwner.current &&
config.__self &&
ReactCurrentOwner.current.stateNode !== config.__self
) {
const componentName = getComponentName(ReactCurrentOwner.current.type);
if (!didWarnAboutStringRefs[componentName]) {
console.error(
'Component "%s" contains the string ref "%s". ' +
'Support for string refs will be removed in a future major release. ' +
'This case cannot be automatically converted to an arrow function. ' +
'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
'Learn more about using refs safely here: ' +
'https://fb.me/react-strict-mode-string-ref',
getComponentName(ReactCurrentOwner.current.type),
config.ref,
);
didWarnAboutStringRefs[componentName] = true;
}
}
}
}
/**
* Factory method to create a new React element. This no longer adheres to
* the class pattern, so do not use new to call it. Also, instanceof check
@@ -260,6 +294,7 @@ export function jsxDEV(type, config, maybeKey, source, self) {
if (hasValidRef(config)) {
ref = config.ref;
warnIfStringRefCannotBeAutoConverted(config);
}
// Remaining properties are added to a new props object
@@ -324,6 +359,10 @@ export function createElement(type, config, children) {
if (config != null) {
if (hasValidRef(config)) {
ref = config.ref;
if (__DEV__) {
warnIfStringRefCannotBeAutoConverted(config);
}
}
if (hasValidKey(config)) {
key = '' + config.key;