Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,24 @@
'use strict';

let React;
let ReactTestUtils;
let ReactFeatureFlags;
let ReactNoop;
let Scheduler;

describe('ReactDeprecationWarnings', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactTestUtils = require('react-dom/test-utils');
ReactNoop = require('react-noop-renderer');
Scheduler = require('scheduler');
ReactFeatureFlags.warnAboutDefaultPropsOnFunctionComponents = true;
ReactFeatureFlags.warnAboutStringRefs = true;
});

afterEach(() => {
ReactFeatureFlags.warnAboutDefaultPropsOnFunctionComponents = false;
ReactFeatureFlags.warnAboutStringRefs = false;
});

it('should warn when given defaultProps', () => {
Expand All @@ -35,13 +39,37 @@ describe('ReactDeprecationWarnings', () => {
testProp: true,
};

expect(() =>
ReactTestUtils.renderIntoDocument(<FunctionalComponent />),
).toWarnDev(
ReactNoop.render(<FunctionalComponent />);
expect(() => expect(Scheduler).toFlushWithoutYielding()).toWarnDev(
'Warning: FunctionalComponent: Support for defaultProps ' +
'will be removed from function components in a future major ' +
'release. Use JavaScript default parameters instead.',
{withoutStack: true},
);
});

it('should warn when given string refs', () => {
class RefComponent extends React.Component {
render() {
return null;
}
}
class Component extends React.Component {
render() {
return <RefComponent ref="refComponent" />;
}
}

ReactNoop.render(<Component />);
expect(() => expect(Scheduler).toFlushWithoutYielding()).toWarnDev(
'Warning: Component "Component" contains the string ref "refComponent". ' +
'Support for string refs will be removed in a future major release. ' +
'We recommend using useRef() or createRef() instead.' +
'\n\n' +
' in Component (at **)' +
'\n\n' +
'Learn more about using refs safely here:\n' +
'https://fb.me/react-strict-mode-string-ref',
);
});
});
50 changes: 34 additions & 16 deletions packages/react-reconciler/src/ReactChildFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
import invariant from 'shared/invariant';
import warning from 'shared/warning';
import warningWithoutStack from 'shared/warningWithoutStack';
import {warnAboutStringRefs} from 'shared/ReactFeatureFlags';

import {
createWorkInProgress,
Expand All @@ -49,15 +50,15 @@ import {StrictMode} from './ReactTypeOfMode';

let didWarnAboutMaps;
let didWarnAboutGenerators;
let didWarnAboutStringRefInStrictMode;
let didWarnAboutStringRefs;
let ownerHasKeyUseWarning;
let ownerHasFunctionTypeWarning;
let warnForMissingKey = (child: mixed) => {};

if (__DEV__) {
didWarnAboutMaps = false;
didWarnAboutGenerators = false;
didWarnAboutStringRefInStrictMode = {};
didWarnAboutStringRefs = {};

/**
* Warn if there's no key explicitly set on dynamic arrays of children or
Expand Down Expand Up @@ -114,21 +115,38 @@ function coerceRef(
typeof mixedRef !== 'object'
) {
if (__DEV__) {
if (returnFiber.mode & StrictMode) {
// 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) {
const componentName = getComponentName(returnFiber.type) || 'Component';
if (!didWarnAboutStringRefInStrictMode[componentName]) {
warningWithoutStack(
false,
'A string ref, "%s", has been found within a strict mode tree. ' +
'String refs are a source of potential bugs and should be avoided. ' +
'We recommend using createRef() instead.' +
'\n%s' +
'\n\nLearn more about using refs safely here:' +
'\nhttps://fb.me/react-strict-mode-string-ref',
mixedRef,
getStackByFiberInDevAndProd(returnFiber),
);
didWarnAboutStringRefInStrictMode[componentName] = true;
if (!didWarnAboutStringRefs[componentName]) {
if (warnAboutStringRefs) {
warningWithoutStack(
false,
'Component "%s" contains the string ref "%s". Support for string refs ' +
'will be removed in a future major release. We recommend using ' +
'useRef() or createRef() instead.' +
'\n%s' +
'\n\nLearn more about using refs safely here:' +
'\nhttps://fb.me/react-strict-mode-string-ref',
componentName,
mixedRef,
getStackByFiberInDevAndProd(returnFiber),
);
} else {
warningWithoutStack(
false,
'A string ref, "%s", has been found within a strict mode tree. ' +
'String refs are a source of potential bugs and should be avoided. ' +
'We recommend using useRef() or createRef() instead.' +
'\n%s' +
'\n\nLearn more about using refs safely here:' +
'\nhttps://fb.me/react-strict-mode-string-ref',
mixedRef,
getStackByFiberInDevAndProd(returnFiber),
);
}
didWarnAboutStringRefs[componentName] = true;
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/__tests__/ReactStrictMode-test.internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ Please update the following components: Parent`,
}).toWarnDev(
'Warning: A string ref, "somestring", has been found within a strict mode tree. ' +
'String refs are a source of potential bugs and should be avoided. ' +
'We recommend using createRef() instead.\n\n' +
'We recommend using useRef() or createRef() instead.\n\n' +
' in StrictMode (at **)\n' +
' in OuterComponent (at **)\n\n' +
'Learn more about using refs safely here:\n' +
Expand Down Expand Up @@ -735,7 +735,7 @@ Please update the following components: Parent`,
}).toWarnDev(
'Warning: A string ref, "somestring", has been found within a strict mode tree. ' +
'String refs are a source of potential bugs and should be avoided. ' +
'We recommend using createRef() instead.\n\n' +
'We recommend using useRef() or createRef() instead.\n\n' +
' in InnerComponent (at **)\n' +
' in StrictMode (at **)\n' +
' in OuterComponent (at **)\n\n' +
Expand Down
1 change: 1 addition & 0 deletions packages/shared/ReactFeatureFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,6 @@ export const enableSuspenseCallback = false;
// from React.createElement to React.jsx
// https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md
export const warnAboutDefaultPropsOnFunctionComponents = false;
export const warnAboutStringRefs = false;

export const disableLegacyContext = false;
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const flushSuspenseFallbacksInTests = true;
export const enableUserBlockingEvents = false;
export const enableSuspenseCallback = false;
export const warnAboutDefaultPropsOnFunctionComponents = false;
export const warnAboutStringRefs = false;
export const disableLegacyContext = false;

// Only used in www builds.
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-oss.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const flushSuspenseFallbacksInTests = true;
export const enableUserBlockingEvents = false;
export const enableSuspenseCallback = false;
export const warnAboutDefaultPropsOnFunctionComponents = false;
export const warnAboutStringRefs = false;
export const disableLegacyContext = false;

// Only used in www builds.
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.persistent.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const flushSuspenseFallbacksInTests = true;
export const enableUserBlockingEvents = false;
export const enableSuspenseCallback = false;
export const warnAboutDefaultPropsOnFunctionComponents = false;
export const warnAboutStringRefs = false;
export const disableLegacyContext = false;

// Only used in www builds.
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.test-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const flushSuspenseFallbacksInTests = true;
export const enableUserBlockingEvents = false;
export const enableSuspenseCallback = false;
export const warnAboutDefaultPropsOnFunctionComponents = false;
export const warnAboutStringRefs = false;
export const disableLegacyContext = false;

// Only used in www builds.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const flushSuspenseFallbacksInTests = true;
export const enableUserBlockingEvents = false;
export const enableSuspenseCallback = true;
export const warnAboutDefaultPropsOnFunctionComponents = false;
export const warnAboutStringRefs = false;
export const disableLegacyContext = false;

// Only used in www builds.
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/forks/ReactFeatureFlags.www.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ export const enableSuspenseCallback = true;

export const warnAboutDefaultPropsOnFunctionComponents = false;

export const warnAboutStringRefs = false;

export const flushSuspenseFallbacksInTests = true;

// Flow magic to verify the exports of this file match the original version.
Expand Down