Skip to content

Commit

Permalink
Remove defaultProps support (except for classes) (#28733)
Browse files Browse the repository at this point in the history
This removes defaultProps support for all component types except for
classes. We've chosen to continue supporting defaultProps for classes
because lots of older code relies on it, and unlike function components,
(which can use default params), there's no straightforward alternative.

By implication, it also removes support for setting defaultProps on
`React.lazy` wrapper. So this will not work:

```js
const MyClassComponent = React.lazy(() => import('./MyClassComponent'));
// MyClassComponent is not actually a class; it's a lazy wrapper. So
// defaultProps does not work.
MyClassComponent.defaultProps = { foo: 'bar' };
```

However, if you set the default props on the class itself, then it's
fine.

For classes, this change also moves where defaultProps are resolved.
Previously, defaultProps were resolved by the JSX runtime. This change
is only observable if you introspect a JSX element, which is relatively
rare but does happen.

In other words, previously `<ClassWithDefaultProp />.props.aDefaultProp`
would resolve to the default prop value, but now it does not.

DiffTrain build for [48b4ecc](48b4ecc)
  • Loading branch information
acdlite committed Apr 4, 2024
1 parent e0fc90e commit 769be69
Show file tree
Hide file tree
Showing 34 changed files with 1,691 additions and 1,052 deletions.
20 changes: 12 additions & 8 deletions compiled/facebook-www/JSXDEVRuntime-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ if (__DEV__) {
var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing,
enableTransitionTracing = dynamicFeatureFlags.enableTransitionTracing,
enableRenderableContext = dynamicFeatureFlags.enableRenderableContext,
enableRefAsProp = dynamicFeatureFlags.enableRefAsProp;
// On WWW, false is used for a new modern build.
enableRefAsProp = dynamicFeatureFlags.enableRefAsProp,
disableDefaultPropsExceptForClasses =
dynamicFeatureFlags.disableDefaultPropsExceptForClasses; // On WWW, false is used for a new modern build.

function getWrappedName(outerType, innerType, wrapperName) {
var displayName = outerType.displayName;
Expand Down Expand Up @@ -1231,14 +1232,17 @@ if (__DEV__) {
) {
props[propName] = config[propName];
}
} // Resolve default props
}

if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
if (!disableDefaultPropsExceptForClasses) {
// Resolve default props
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;

for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
}
Expand Down
20 changes: 12 additions & 8 deletions compiled/facebook-www/JSXDEVRuntime-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ if (__DEV__) {
var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing,
enableTransitionTracing = dynamicFeatureFlags.enableTransitionTracing,
enableRenderableContext = dynamicFeatureFlags.enableRenderableContext,
enableRefAsProp = dynamicFeatureFlags.enableRefAsProp;
// On WWW, true is used for a new modern build.
enableRefAsProp = dynamicFeatureFlags.enableRefAsProp,
disableDefaultPropsExceptForClasses =
dynamicFeatureFlags.disableDefaultPropsExceptForClasses; // On WWW, true is used for a new modern build.

function getWrappedName(outerType, innerType, wrapperName) {
var displayName = outerType.displayName;
Expand Down Expand Up @@ -1231,14 +1232,17 @@ if (__DEV__) {
) {
props[propName] = config[propName];
}
} // Resolve default props
}

if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
if (!disableDefaultPropsExceptForClasses) {
// Resolve default props
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;

for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6090cab099a8f7f373e04c7eb2937425a8f80f80
48b4ecc9012638ed51b275aad24b2086b8215e32
104 changes: 48 additions & 56 deletions compiled/facebook-www/React-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if (__DEV__) {
) {
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
}
var ReactVersion = "19.0.0-www-classic-308d9210";
var ReactVersion = "19.0.0-www-classic-b9e0eea7";

// ATTENTION
// When adding new symbols to this file,
Expand Down Expand Up @@ -475,8 +475,9 @@ if (__DEV__) {
var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing,
enableTransitionTracing = dynamicFeatureFlags.enableTransitionTracing,
enableRenderableContext = dynamicFeatureFlags.enableRenderableContext,
enableRefAsProp = dynamicFeatureFlags.enableRefAsProp;
// On WWW, false is used for a new modern build.
enableRefAsProp = dynamicFeatureFlags.enableRefAsProp,
disableDefaultPropsExceptForClasses =
dynamicFeatureFlags.disableDefaultPropsExceptForClasses; // On WWW, false is used for a new modern build.
var disableLegacyMode = false;

function getWrappedName(outerType, innerType, wrapperName) {
Expand Down Expand Up @@ -1639,14 +1640,17 @@ if (__DEV__) {
) {
props[propName] = config[propName];
}
} // Resolve default props
}

if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
if (!disableDefaultPropsExceptForClasses) {
// Resolve default props
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;

for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
}
Expand Down Expand Up @@ -1906,7 +1910,11 @@ if (__DEV__) {

var defaultProps;

if (element.type && element.type.defaultProps) {
if (
!disableDefaultPropsExceptForClasses &&
element.type &&
element.type.defaultProps
) {
defaultProps = element.type.defaultProps;
}

Expand All @@ -1926,7 +1934,11 @@ if (__DEV__) {
// backwards compatibility.
!(enableRefAsProp && propName === "ref" && config.ref === undefined)
) {
if (config[propName] === undefined && defaultProps !== undefined) {
if (
!disableDefaultPropsExceptForClasses &&
config[propName] === undefined &&
defaultProps !== undefined
) {
// Resolve default props
props[propName] = defaultProps[propName];
} else {
Expand Down Expand Up @@ -2765,55 +2777,35 @@ if (__DEV__) {
_init: lazyInitializer
};

{
// In production, this would just set it on the object.
var defaultProps;
var propTypes; // $FlowFixMe[prop-missing]

Object.defineProperties(lazyType, {
defaultProps: {
configurable: true,
get: function () {
return defaultProps;
},
// $FlowFixMe[missing-local-annot]
set: function (newDefaultProps) {
error(
"It is not supported to assign `defaultProps` to " +
"a lazy component import. Either specify them where the component " +
"is defined, or create a wrapping component around it."
);

defaultProps = newDefaultProps; // Match production behavior more closely:
// $FlowFixMe[prop-missing]
if (!disableDefaultPropsExceptForClasses) {
{
// In production, this would just set it on the object.
var defaultProps; // $FlowFixMe[prop-missing]

Object.defineProperty(lazyType, "defaultProps", {
enumerable: true
});
}
},
propTypes: {
configurable: true,
get: function () {
return propTypes;
},
// $FlowFixMe[missing-local-annot]
set: function (newPropTypes) {
error(
"It is not supported to assign `propTypes` to " +
"a lazy component import. Either specify them where the component " +
"is defined, or create a wrapping component around it."
);
Object.defineProperties(lazyType, {
defaultProps: {
configurable: true,
get: function () {
return defaultProps;
},
// $FlowFixMe[missing-local-annot]
set: function (newDefaultProps) {
error(
"It is not supported to assign `defaultProps` to " +
"a lazy component import. Either specify them where the component " +
"is defined, or create a wrapping component around it."
);

propTypes = newPropTypes; // Match production behavior more closely:
// $FlowFixMe[prop-missing]
defaultProps = newDefaultProps; // Match production behavior more closely:
// $FlowFixMe[prop-missing]

Object.defineProperty(lazyType, "propTypes", {
enumerable: true
});
Object.defineProperty(lazyType, "defaultProps", {
enumerable: true
});
}
}
}
});
});
}
}

return lazyType;
Expand Down
104 changes: 48 additions & 56 deletions compiled/facebook-www/React-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if (__DEV__) {
) {
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
}
var ReactVersion = "19.0.0-www-modern-3e52800d";
var ReactVersion = "19.0.0-www-modern-3a8173ed";

// ATTENTION
// When adding new symbols to this file,
Expand Down Expand Up @@ -475,8 +475,9 @@ if (__DEV__) {
var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing,
enableTransitionTracing = dynamicFeatureFlags.enableTransitionTracing,
enableRenderableContext = dynamicFeatureFlags.enableRenderableContext,
enableRefAsProp = dynamicFeatureFlags.enableRefAsProp;
// On WWW, true is used for a new modern build.
enableRefAsProp = dynamicFeatureFlags.enableRefAsProp,
disableDefaultPropsExceptForClasses =
dynamicFeatureFlags.disableDefaultPropsExceptForClasses; // On WWW, true is used for a new modern build.
var disableLegacyMode = true;

function getWrappedName(outerType, innerType, wrapperName) {
Expand Down Expand Up @@ -1639,14 +1640,17 @@ if (__DEV__) {
) {
props[propName] = config[propName];
}
} // Resolve default props
}

if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
if (!disableDefaultPropsExceptForClasses) {
// Resolve default props
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;

for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
}
Expand Down Expand Up @@ -1906,7 +1910,11 @@ if (__DEV__) {

var defaultProps;

if (element.type && element.type.defaultProps) {
if (
!disableDefaultPropsExceptForClasses &&
element.type &&
element.type.defaultProps
) {
defaultProps = element.type.defaultProps;
}

Expand All @@ -1926,7 +1934,11 @@ if (__DEV__) {
// backwards compatibility.
!(enableRefAsProp && propName === "ref" && config.ref === undefined)
) {
if (config[propName] === undefined && defaultProps !== undefined) {
if (
!disableDefaultPropsExceptForClasses &&
config[propName] === undefined &&
defaultProps !== undefined
) {
// Resolve default props
props[propName] = defaultProps[propName];
} else {
Expand Down Expand Up @@ -2765,55 +2777,35 @@ if (__DEV__) {
_init: lazyInitializer
};

{
// In production, this would just set it on the object.
var defaultProps;
var propTypes; // $FlowFixMe[prop-missing]

Object.defineProperties(lazyType, {
defaultProps: {
configurable: true,
get: function () {
return defaultProps;
},
// $FlowFixMe[missing-local-annot]
set: function (newDefaultProps) {
error(
"It is not supported to assign `defaultProps` to " +
"a lazy component import. Either specify them where the component " +
"is defined, or create a wrapping component around it."
);

defaultProps = newDefaultProps; // Match production behavior more closely:
// $FlowFixMe[prop-missing]
if (!disableDefaultPropsExceptForClasses) {
{
// In production, this would just set it on the object.
var defaultProps; // $FlowFixMe[prop-missing]

Object.defineProperty(lazyType, "defaultProps", {
enumerable: true
});
}
},
propTypes: {
configurable: true,
get: function () {
return propTypes;
},
// $FlowFixMe[missing-local-annot]
set: function (newPropTypes) {
error(
"It is not supported to assign `propTypes` to " +
"a lazy component import. Either specify them where the component " +
"is defined, or create a wrapping component around it."
);
Object.defineProperties(lazyType, {
defaultProps: {
configurable: true,
get: function () {
return defaultProps;
},
// $FlowFixMe[missing-local-annot]
set: function (newDefaultProps) {
error(
"It is not supported to assign `defaultProps` to " +
"a lazy component import. Either specify them where the component " +
"is defined, or create a wrapping component around it."
);

propTypes = newPropTypes; // Match production behavior more closely:
// $FlowFixMe[prop-missing]
defaultProps = newDefaultProps; // Match production behavior more closely:
// $FlowFixMe[prop-missing]

Object.defineProperty(lazyType, "propTypes", {
enumerable: true
});
Object.defineProperty(lazyType, "defaultProps", {
enumerable: true
});
}
}
}
});
});
}
}

return lazyType;
Expand Down
Loading

0 comments on commit 769be69

Please sign in to comment.