mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Warn if outdated JSX transform is detected (#28781)
We want to warn if we detect that an app is using an outdated JSX transform. We can't just warn if `createElement` is called because we still support `createElement` when it's called manually. We only want to warn if `createElement` is output by the compiler. The heuristic is to check for a `__self` prop, which is an optional, internal prop that older transforms used to pass to `createElement` for better debugging in development mode. If `__self` is present, we `console.warn` once with advice to upgrade to the modern JSX transform. Subsequent elements will not warn. There's a special case we have to account for: when a static "key" prop is defined _after_ a spread, the modern JSX transform outputs `createElement` instead of `jsx`. (This is because with `jsx`, a spread key always takes precedence over a static key, regardless of the order, whereas `createElement` respects the order.) To avoid a false positive warning, we skip the warning whenever a `key` prop is present.
This commit is contained in:
@@ -91,6 +91,9 @@ describe('ReactDeprecationWarnings', () => {
|
||||
);
|
||||
});
|
||||
|
||||
// Disabling this until #28732 lands so we can assert on the warning message.
|
||||
// (It's already disabled in all but the Meta builds, anyway. Nbd.)
|
||||
// @gate TODO || !__DEV__
|
||||
// @gate !disableStringRefs
|
||||
it('should warn when owner and self are the same for string refs', async () => {
|
||||
class RefComponent extends React.Component {
|
||||
@@ -114,8 +117,11 @@ describe('ReactDeprecationWarnings', () => {
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
// Disabling this until #28732 lands so we can assert on the warning message.
|
||||
// (It's already disabled in all but the Meta builds, anyway. Nbd.)
|
||||
// @gate TODO || !__DEV__
|
||||
// @gate !disableStringRefs
|
||||
it('should warn when owner and self are different for string refs', async () => {
|
||||
it('should warn when owner and self are different for string refs (createElement)', async () => {
|
||||
class RefComponent extends React.Component {
|
||||
render() {
|
||||
return null;
|
||||
@@ -143,7 +149,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
|
||||
// @gate __DEV__
|
||||
// @gate !disableStringRefs
|
||||
it('should warn when owner and self are different for string refs', async () => {
|
||||
it('should warn when owner and self are different for string refs (jsx)', async () => {
|
||||
class RefComponent extends React.Component {
|
||||
render() {
|
||||
return null;
|
||||
|
||||
@@ -466,4 +466,31 @@ describe('ReactCreateElement', () => {
|
||||
});
|
||||
expect(test.props.value).toBeNaN();
|
||||
});
|
||||
|
||||
it('warns if outdated JSX transform is detected', async () => {
|
||||
// Warns if __self is detected, because that's only passed by a compiler
|
||||
expect(() => {
|
||||
React.createElement('div', {className: 'foo', __self: this});
|
||||
}).toWarnDev(
|
||||
'Your app (or one of its dependencies) is using an outdated ' +
|
||||
'JSX transform.',
|
||||
{
|
||||
withoutStack: true,
|
||||
},
|
||||
);
|
||||
|
||||
// Only warns the first time. Subsequent elements don't warn.
|
||||
React.createElement('div', {className: 'foo', __self: this});
|
||||
});
|
||||
|
||||
it('do not warn about outdated JSX transform if `key` is present', () => {
|
||||
// When a static "key" prop is defined _after_ a spread, the modern JSX
|
||||
// transform outputs `createElement` instead of `jsx`. (This is because with
|
||||
// `jsx`, a spread key always takes precedence over a static key, regardless
|
||||
// of the order, whereas `createElement` respects the order.)
|
||||
//
|
||||
// To avoid a false positive warning, we skip the warning whenever a `key`
|
||||
// prop is present.
|
||||
React.createElement('div', {key: 'foo', __self: this});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,6 +33,7 @@ let specialPropKeyWarningShown;
|
||||
let specialPropRefWarningShown;
|
||||
let didWarnAboutStringRefs;
|
||||
let didWarnAboutElementRef;
|
||||
let didWarnAboutOldJSXRuntime;
|
||||
|
||||
if (__DEV__) {
|
||||
didWarnAboutStringRefs = {};
|
||||
@@ -722,6 +723,28 @@ export function createElement(type, config, children) {
|
||||
let ref = null;
|
||||
|
||||
if (config != null) {
|
||||
if (__DEV__) {
|
||||
if (
|
||||
!didWarnAboutOldJSXRuntime &&
|
||||
'__self' in config &&
|
||||
// Do not assume this is the result of an oudated JSX transform if key
|
||||
// is present, because the modern JSX transform sometimes outputs
|
||||
// createElement to preserve precedence between a static key and a
|
||||
// spread key. To avoid false positive warnings, we never warn if
|
||||
// there's a key.
|
||||
!('key' in config)
|
||||
) {
|
||||
didWarnAboutOldJSXRuntime = true;
|
||||
console.warn(
|
||||
'Your app (or one of its dependencies) is using an outdated JSX ' +
|
||||
'transform. Update to the modern JSX transform for ' +
|
||||
'faster performance: ' +
|
||||
// TODO: Create a short link for this
|
||||
'https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasValidRef(config)) {
|
||||
if (!enableRefAsProp) {
|
||||
ref = config.ref;
|
||||
|
||||
Reference in New Issue
Block a user