From 2cfe8d32dddfe9e3fa57cef5835e57297231b12c Mon Sep 17 00:00:00 2001 From: acdlite Date: Fri, 5 Apr 2024 17:30:21 +0000 Subject: [PATCH] Fast JSX: Don't clone props object (#28768) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (Unless "key" is spread onto the element.) Historically, the JSX runtime clones the props object that is passed in. We've done this for two reasons. One reason is that there are certain prop names that are reserved by React, like `key` and (before React 19) `ref`. These are not actual props and are not observable by the target component; React uses them internally but removes them from the props object before passing them to userspace. The second reason is that the classic JSX runtime, `createElement`, is both a compiler target _and_ a public API that can be called manually. Therefore, we can't assume that the props object that is passed into `createElement` won't be mutated by userspace code after it is passed in. However, the new JSX runtime, `jsx`, is not a public API — it's solely a compiler target, and the compiler _will_ always pass a fresh, inline object. So the only reason to clone the props is if a reserved prop name is used. In React 19, `ref` is no longer a reserved prop name, and `key` will only appear in the props object if it is spread onto the element. (Because if `key` is statically defined, the compiler will pass it as a separate argument to the `jsx` function.) So the only remaining reason to clone the props object is if `key` is spread onto the element, which is a rare case, and also triggers a warning in development. In a future release, we will not remove a spread key from the props object. (But we'll still warn.) We'll always pass the object straight through. The expected impact is much faster JSX element creation, which in many apps is a significant slice of the overall runtime cost of rendering. DiffTrain build for [d1547defe34cee6326a61059148afc83228d8ecf](https://github.com/facebook/react/commit/d1547defe34cee6326a61059148afc83228d8ecf) --- .../facebook-www/JSXDEVRuntime-dev.classic.js | 59 +++++++++++------- .../facebook-www/JSXDEVRuntime-dev.modern.js | 59 +++++++++++------- compiled/facebook-www/REVISION | 2 +- compiled/facebook-www/React-dev.classic.js | 61 ++++++++++++------- compiled/facebook-www/React-dev.modern.js | 61 ++++++++++++------- compiled/facebook-www/React-prod.classic.js | 24 ++++---- compiled/facebook-www/React-prod.modern.js | 24 ++++---- .../facebook-www/React-profiling.classic.js | 24 ++++---- .../facebook-www/React-profiling.modern.js | 24 ++++---- .../facebook-www/ReactServer-dev.modern.js | 61 ++++++++++++------- .../facebook-www/ReactServer-prod.modern.js | 24 ++++---- 11 files changed, 259 insertions(+), 164 deletions(-) diff --git a/compiled/facebook-www/JSXDEVRuntime-dev.classic.js b/compiled/facebook-www/JSXDEVRuntime-dev.classic.js index 82a8dffded61d..8a6986066922e 100644 --- a/compiled/facebook-www/JSXDEVRuntime-dev.classic.js +++ b/compiled/facebook-www/JSXDEVRuntime-dev.classic.js @@ -1352,9 +1352,6 @@ if (__DEV__) { } } - var propName; // Reserved names are extracted - - var props = {}; var key = null; var ref = null; // Currently, key can be spread in as a prop. This causes a potential // issue if key is also explicitly declared (ie.
@@ -1391,22 +1388,42 @@ if (__DEV__) { { warnIfStringRefCannotBeAutoConverted(config, self); } - } // Remaining properties are added to a new props object + } - for (propName in config) { - if ( - hasOwnProperty.call(config, propName) && // Skip over reserved prop names - propName !== "key" && - (enableRefAsProp || propName !== "ref") - ) { - if (enableRefAsProp && !disableStringRefs && propName === "ref") { - props.ref = coerceStringRef( - config[propName], - ReactCurrentOwner.current, - type - ); - } else { - props[propName] = config[propName]; + var props; + + if (enableRefAsProp && disableStringRefs && !("key" in config)) { + // If key was not spread in, we can reuse the original props object. This + // only works for `jsx`, not `createElement`, because `jsx` is a compiler + // target and the compiler always passes a new object. For `createElement`, + // we can't assume a new object is passed every time because it can be + // called manually. + // + // Spreading key is a warning in dev. In a future release, we will not + // remove a spread key from the props object. (But we'll still warn.) We'll + // always pass the object straight through. + props = config; + } else { + // We need to remove reserved props (key, prop, ref). Create a fresh props + // object and copy over all the non-reserved props. We don't use `delete` + // because in V8 it will deopt the object to dictionary mode. + props = {}; + + for (var propName in config) { + if ( + hasOwnProperty.call(config, propName) && // Skip over reserved prop names + propName !== "key" && + (enableRefAsProp || propName !== "ref") + ) { + if (enableRefAsProp && !disableStringRefs && propName === "ref") { + props.ref = coerceStringRef( + config[propName], + ReactCurrentOwner.current, + type + ); + } else { + props[propName] = config[propName]; + } } } } @@ -1416,9 +1433,9 @@ if (__DEV__) { if (type && type.defaultProps) { var defaultProps = type.defaultProps; - for (propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; + for (var _propName2 in defaultProps) { + if (props[_propName2] === undefined) { + props[_propName2] = defaultProps[_propName2]; } } } diff --git a/compiled/facebook-www/JSXDEVRuntime-dev.modern.js b/compiled/facebook-www/JSXDEVRuntime-dev.modern.js index 858d8b1a79c43..bda96ae087db4 100644 --- a/compiled/facebook-www/JSXDEVRuntime-dev.modern.js +++ b/compiled/facebook-www/JSXDEVRuntime-dev.modern.js @@ -1354,9 +1354,6 @@ if (__DEV__) { } } - var propName; // Reserved names are extracted - - var props = {}; var key = null; var ref = null; // Currently, key can be spread in as a prop. This causes a potential // issue if key is also explicitly declared (ie.
@@ -1393,22 +1390,42 @@ if (__DEV__) { { warnIfStringRefCannotBeAutoConverted(config, self); } - } // Remaining properties are added to a new props object + } - for (propName in config) { - if ( - hasOwnProperty.call(config, propName) && // Skip over reserved prop names - propName !== "key" && - (enableRefAsProp || propName !== "ref") - ) { - if (enableRefAsProp && !disableStringRefs && propName === "ref") { - props.ref = coerceStringRef( - config[propName], - ReactCurrentOwner.current, - type - ); - } else { - props[propName] = config[propName]; + var props; + + if (enableRefAsProp && disableStringRefs && !("key" in config)) { + // If key was not spread in, we can reuse the original props object. This + // only works for `jsx`, not `createElement`, because `jsx` is a compiler + // target and the compiler always passes a new object. For `createElement`, + // we can't assume a new object is passed every time because it can be + // called manually. + // + // Spreading key is a warning in dev. In a future release, we will not + // remove a spread key from the props object. (But we'll still warn.) We'll + // always pass the object straight through. + props = config; + } else { + // We need to remove reserved props (key, prop, ref). Create a fresh props + // object and copy over all the non-reserved props. We don't use `delete` + // because in V8 it will deopt the object to dictionary mode. + props = {}; + + for (var propName in config) { + if ( + hasOwnProperty.call(config, propName) && // Skip over reserved prop names + propName !== "key" && + (enableRefAsProp || propName !== "ref") + ) { + if (enableRefAsProp && !disableStringRefs && propName === "ref") { + props.ref = coerceStringRef( + config[propName], + ReactCurrentOwner.current, + type + ); + } else { + props[propName] = config[propName]; + } } } } @@ -1418,9 +1435,9 @@ if (__DEV__) { if (type && type.defaultProps) { var defaultProps = type.defaultProps; - for (propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; + for (var _propName2 in defaultProps) { + if (props[_propName2] === undefined) { + props[_propName2] = defaultProps[_propName2]; } } } diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index 8e5b45b2ef9a9..ffb9c9016f33a 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -bfd8da807c75a2d123627415f9eaf2d36ac3ed6a +d1547defe34cee6326a61059148afc83228d8ecf diff --git a/compiled/facebook-www/React-dev.classic.js b/compiled/facebook-www/React-dev.classic.js index 304da4dfe8b44..81f0458c13b99 100644 --- a/compiled/facebook-www/React-dev.classic.js +++ b/compiled/facebook-www/React-dev.classic.js @@ -24,7 +24,7 @@ if (__DEV__) { ) { __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); } - var ReactVersion = "19.0.0-www-classic-ff21e352"; + var ReactVersion = "19.0.0-www-classic-4511ca3e"; // ATTENTION // When adding new symbols to this file, @@ -1760,9 +1760,6 @@ if (__DEV__) { } } - var propName; // Reserved names are extracted - - var props = {}; var key = null; var ref = null; // Currently, key can be spread in as a prop. This causes a potential // issue if key is also explicitly declared (ie.
@@ -1799,22 +1796,42 @@ if (__DEV__) { { warnIfStringRefCannotBeAutoConverted(config, self); } - } // Remaining properties are added to a new props object + } - for (propName in config) { - if ( - hasOwnProperty.call(config, propName) && // Skip over reserved prop names - propName !== "key" && - (enableRefAsProp || propName !== "ref") - ) { - if (enableRefAsProp && !disableStringRefs && propName === "ref") { - props.ref = coerceStringRef( - config[propName], - ReactCurrentOwner.current, - type - ); - } else { - props[propName] = config[propName]; + var props; + + if (enableRefAsProp && disableStringRefs && !("key" in config)) { + // If key was not spread in, we can reuse the original props object. This + // only works for `jsx`, not `createElement`, because `jsx` is a compiler + // target and the compiler always passes a new object. For `createElement`, + // we can't assume a new object is passed every time because it can be + // called manually. + // + // Spreading key is a warning in dev. In a future release, we will not + // remove a spread key from the props object. (But we'll still warn.) We'll + // always pass the object straight through. + props = config; + } else { + // We need to remove reserved props (key, prop, ref). Create a fresh props + // object and copy over all the non-reserved props. We don't use `delete` + // because in V8 it will deopt the object to dictionary mode. + props = {}; + + for (var propName in config) { + if ( + hasOwnProperty.call(config, propName) && // Skip over reserved prop names + propName !== "key" && + (enableRefAsProp || propName !== "ref") + ) { + if (enableRefAsProp && !disableStringRefs && propName === "ref") { + props.ref = coerceStringRef( + config[propName], + ReactCurrentOwner.current, + type + ); + } else { + props[propName] = config[propName]; + } } } } @@ -1824,9 +1841,9 @@ if (__DEV__) { if (type && type.defaultProps) { var defaultProps = type.defaultProps; - for (propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; + for (var _propName2 in defaultProps) { + if (props[_propName2] === undefined) { + props[_propName2] = defaultProps[_propName2]; } } } diff --git a/compiled/facebook-www/React-dev.modern.js b/compiled/facebook-www/React-dev.modern.js index d614853e50b8e..0dd55f2e82395 100644 --- a/compiled/facebook-www/React-dev.modern.js +++ b/compiled/facebook-www/React-dev.modern.js @@ -24,7 +24,7 @@ if (__DEV__) { ) { __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); } - var ReactVersion = "19.0.0-www-modern-99738e97"; + var ReactVersion = "19.0.0-www-modern-8e3891bc"; // ATTENTION // When adding new symbols to this file, @@ -1762,9 +1762,6 @@ if (__DEV__) { } } - var propName; // Reserved names are extracted - - var props = {}; var key = null; var ref = null; // Currently, key can be spread in as a prop. This causes a potential // issue if key is also explicitly declared (ie.
@@ -1801,22 +1798,42 @@ if (__DEV__) { { warnIfStringRefCannotBeAutoConverted(config, self); } - } // Remaining properties are added to a new props object + } - for (propName in config) { - if ( - hasOwnProperty.call(config, propName) && // Skip over reserved prop names - propName !== "key" && - (enableRefAsProp || propName !== "ref") - ) { - if (enableRefAsProp && !disableStringRefs && propName === "ref") { - props.ref = coerceStringRef( - config[propName], - ReactCurrentOwner.current, - type - ); - } else { - props[propName] = config[propName]; + var props; + + if (enableRefAsProp && disableStringRefs && !("key" in config)) { + // If key was not spread in, we can reuse the original props object. This + // only works for `jsx`, not `createElement`, because `jsx` is a compiler + // target and the compiler always passes a new object. For `createElement`, + // we can't assume a new object is passed every time because it can be + // called manually. + // + // Spreading key is a warning in dev. In a future release, we will not + // remove a spread key from the props object. (But we'll still warn.) We'll + // always pass the object straight through. + props = config; + } else { + // We need to remove reserved props (key, prop, ref). Create a fresh props + // object and copy over all the non-reserved props. We don't use `delete` + // because in V8 it will deopt the object to dictionary mode. + props = {}; + + for (var propName in config) { + if ( + hasOwnProperty.call(config, propName) && // Skip over reserved prop names + propName !== "key" && + (enableRefAsProp || propName !== "ref") + ) { + if (enableRefAsProp && !disableStringRefs && propName === "ref") { + props.ref = coerceStringRef( + config[propName], + ReactCurrentOwner.current, + type + ); + } else { + props[propName] = config[propName]; + } } } } @@ -1826,9 +1843,9 @@ if (__DEV__) { if (type && type.defaultProps) { var defaultProps = type.defaultProps; - for (propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; + for (var _propName2 in defaultProps) { + if (props[_propName2] === undefined) { + props[_propName2] = defaultProps[_propName2]; } } } diff --git a/compiled/facebook-www/React-prod.classic.js b/compiled/facebook-www/React-prod.classic.js index 706968843e67a..c45201e53a41a 100644 --- a/compiled/facebook-www/React-prod.classic.js +++ b/compiled/facebook-www/React-prod.classic.js @@ -111,9 +111,7 @@ function ReactElement(type, key, _ref, self, source, owner, props) { }; } function jsxProd(type, config, maybeKey) { - var propName, - props = {}, - key = null, + var key = null, ref = null; void 0 !== maybeKey && (key = "" + maybeKey); void 0 !== config.key && (key = "" + config.key); @@ -121,20 +119,24 @@ function jsxProd(type, config, maybeKey) { enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, ReactCurrentOwner.current, type))); - for (propName in config) + maybeKey = {}; + for (var propName in config) hasOwnProperty.call(config, propName) && "key" !== propName && (enableRefAsProp || "ref" !== propName) && (enableRefAsProp && "ref" === propName - ? (props.ref = coerceStringRef( + ? (maybeKey.ref = coerceStringRef( config[propName], ReactCurrentOwner.current, type )) - : (props[propName] = config[propName])); - if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) - for (propName in ((config = type.defaultProps), config)) - void 0 === props[propName] && (props[propName] = config[propName]); + : (maybeKey[propName] = config[propName])); + if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { + config = type.defaultProps; + for (var propName$0 in config) + void 0 === maybeKey[propName$0] && + (maybeKey[propName$0] = config[propName$0]); + } return ReactElement( type, key, @@ -142,7 +144,7 @@ function jsxProd(type, config, maybeKey) { void 0, void 0, ReactCurrentOwner.current, - props + maybeKey ); } function cloneAndReplaceKey(oldElement, newKey) { @@ -702,4 +704,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactCurrentDispatcher.current.useTransition(); }; -exports.version = "19.0.0-www-classic-9242ce67"; +exports.version = "19.0.0-www-classic-36e8d411"; diff --git a/compiled/facebook-www/React-prod.modern.js b/compiled/facebook-www/React-prod.modern.js index f2c1284b5b8a4..b0d40fd74548c 100644 --- a/compiled/facebook-www/React-prod.modern.js +++ b/compiled/facebook-www/React-prod.modern.js @@ -111,9 +111,7 @@ function ReactElement(type, key, _ref, self, source, owner, props) { }; } function jsxProd(type, config, maybeKey) { - var propName, - props = {}, - key = null, + var key = null, ref = null; void 0 !== maybeKey && (key = "" + maybeKey); void 0 !== config.key && (key = "" + config.key); @@ -121,20 +119,24 @@ function jsxProd(type, config, maybeKey) { enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, ReactCurrentOwner.current, type))); - for (propName in config) + maybeKey = {}; + for (var propName in config) hasOwnProperty.call(config, propName) && "key" !== propName && (enableRefAsProp || "ref" !== propName) && (enableRefAsProp && "ref" === propName - ? (props.ref = coerceStringRef( + ? (maybeKey.ref = coerceStringRef( config[propName], ReactCurrentOwner.current, type )) - : (props[propName] = config[propName])); - if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) - for (propName in ((config = type.defaultProps), config)) - void 0 === props[propName] && (props[propName] = config[propName]); + : (maybeKey[propName] = config[propName])); + if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { + config = type.defaultProps; + for (var propName$0 in config) + void 0 === maybeKey[propName$0] && + (maybeKey[propName$0] = config[propName$0]); + } return ReactElement( type, key, @@ -142,7 +144,7 @@ function jsxProd(type, config, maybeKey) { void 0, void 0, ReactCurrentOwner.current, - props + maybeKey ); } function cloneAndReplaceKey(oldElement, newKey) { @@ -702,4 +704,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactCurrentDispatcher.current.useTransition(); }; -exports.version = "19.0.0-www-modern-9242ce67"; +exports.version = "19.0.0-www-modern-36e8d411"; diff --git a/compiled/facebook-www/React-profiling.classic.js b/compiled/facebook-www/React-profiling.classic.js index dde3c2f5471df..3c663e08d4bf5 100644 --- a/compiled/facebook-www/React-profiling.classic.js +++ b/compiled/facebook-www/React-profiling.classic.js @@ -115,9 +115,7 @@ function ReactElement(type, key, _ref, self, source, owner, props) { }; } function jsxProd(type, config, maybeKey) { - var propName, - props = {}, - key = null, + var key = null, ref = null; void 0 !== maybeKey && (key = "" + maybeKey); void 0 !== config.key && (key = "" + config.key); @@ -125,20 +123,24 @@ function jsxProd(type, config, maybeKey) { enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, ReactCurrentOwner.current, type))); - for (propName in config) + maybeKey = {}; + for (var propName in config) hasOwnProperty.call(config, propName) && "key" !== propName && (enableRefAsProp || "ref" !== propName) && (enableRefAsProp && "ref" === propName - ? (props.ref = coerceStringRef( + ? (maybeKey.ref = coerceStringRef( config[propName], ReactCurrentOwner.current, type )) - : (props[propName] = config[propName])); - if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) - for (propName in ((config = type.defaultProps), config)) - void 0 === props[propName] && (props[propName] = config[propName]); + : (maybeKey[propName] = config[propName])); + if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { + config = type.defaultProps; + for (var propName$0 in config) + void 0 === maybeKey[propName$0] && + (maybeKey[propName$0] = config[propName$0]); + } return ReactElement( type, key, @@ -146,7 +148,7 @@ function jsxProd(type, config, maybeKey) { void 0, void 0, ReactCurrentOwner.current, - props + maybeKey ); } function cloneAndReplaceKey(oldElement, newKey) { @@ -706,7 +708,7 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactCurrentDispatcher.current.useTransition(); }; -exports.version = "19.0.0-www-classic-d6f5b788"; +exports.version = "19.0.0-www-classic-718fc0c7"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/compiled/facebook-www/React-profiling.modern.js b/compiled/facebook-www/React-profiling.modern.js index 1374d74a7bbb1..408a871209c0a 100644 --- a/compiled/facebook-www/React-profiling.modern.js +++ b/compiled/facebook-www/React-profiling.modern.js @@ -115,9 +115,7 @@ function ReactElement(type, key, _ref, self, source, owner, props) { }; } function jsxProd(type, config, maybeKey) { - var propName, - props = {}, - key = null, + var key = null, ref = null; void 0 !== maybeKey && (key = "" + maybeKey); void 0 !== config.key && (key = "" + config.key); @@ -125,20 +123,24 @@ function jsxProd(type, config, maybeKey) { enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, ReactCurrentOwner.current, type))); - for (propName in config) + maybeKey = {}; + for (var propName in config) hasOwnProperty.call(config, propName) && "key" !== propName && (enableRefAsProp || "ref" !== propName) && (enableRefAsProp && "ref" === propName - ? (props.ref = coerceStringRef( + ? (maybeKey.ref = coerceStringRef( config[propName], ReactCurrentOwner.current, type )) - : (props[propName] = config[propName])); - if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) - for (propName in ((config = type.defaultProps), config)) - void 0 === props[propName] && (props[propName] = config[propName]); + : (maybeKey[propName] = config[propName])); + if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { + config = type.defaultProps; + for (var propName$0 in config) + void 0 === maybeKey[propName$0] && + (maybeKey[propName$0] = config[propName$0]); + } return ReactElement( type, key, @@ -146,7 +148,7 @@ function jsxProd(type, config, maybeKey) { void 0, void 0, ReactCurrentOwner.current, - props + maybeKey ); } function cloneAndReplaceKey(oldElement, newKey) { @@ -706,7 +708,7 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactCurrentDispatcher.current.useTransition(); }; -exports.version = "19.0.0-www-modern-d6f5b788"; +exports.version = "19.0.0-www-modern-718fc0c7"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/compiled/facebook-www/ReactServer-dev.modern.js b/compiled/facebook-www/ReactServer-dev.modern.js index 81bab70f89cc7..a91497aae97ad 100644 --- a/compiled/facebook-www/ReactServer-dev.modern.js +++ b/compiled/facebook-www/ReactServer-dev.modern.js @@ -1472,9 +1472,6 @@ if (__DEV__) { } } - var propName; // Reserved names are extracted - - var props = {}; var key = null; var ref = null; // Currently, key can be spread in as a prop. This causes a potential // issue if key is also explicitly declared (ie.
@@ -1511,22 +1508,42 @@ if (__DEV__) { { warnIfStringRefCannotBeAutoConverted(config, self); } - } // Remaining properties are added to a new props object + } - for (propName in config) { - if ( - hasOwnProperty.call(config, propName) && // Skip over reserved prop names - propName !== "key" && - (enableRefAsProp || propName !== "ref") - ) { - if (enableRefAsProp && !disableStringRefs && propName === "ref") { - props.ref = coerceStringRef( - config[propName], - ReactCurrentOwner.current, - type - ); - } else { - props[propName] = config[propName]; + var props; + + if (enableRefAsProp && disableStringRefs && !("key" in config)) { + // If key was not spread in, we can reuse the original props object. This + // only works for `jsx`, not `createElement`, because `jsx` is a compiler + // target and the compiler always passes a new object. For `createElement`, + // we can't assume a new object is passed every time because it can be + // called manually. + // + // Spreading key is a warning in dev. In a future release, we will not + // remove a spread key from the props object. (But we'll still warn.) We'll + // always pass the object straight through. + props = config; + } else { + // We need to remove reserved props (key, prop, ref). Create a fresh props + // object and copy over all the non-reserved props. We don't use `delete` + // because in V8 it will deopt the object to dictionary mode. + props = {}; + + for (var propName in config) { + if ( + hasOwnProperty.call(config, propName) && // Skip over reserved prop names + propName !== "key" && + (enableRefAsProp || propName !== "ref") + ) { + if (enableRefAsProp && !disableStringRefs && propName === "ref") { + props.ref = coerceStringRef( + config[propName], + ReactCurrentOwner.current, + type + ); + } else { + props[propName] = config[propName]; + } } } } @@ -1536,9 +1553,9 @@ if (__DEV__) { if (type && type.defaultProps) { var defaultProps = type.defaultProps; - for (propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; + for (var _propName2 in defaultProps) { + if (props[_propName2] === undefined) { + props[_propName2] = defaultProps[_propName2]; } } } @@ -3117,7 +3134,7 @@ if (__DEV__) { function noop() {} - var ReactVersion = "19.0.0-www-modern-48d37fb2"; + var ReactVersion = "19.0.0-www-modern-4e2ff20e"; // Patch fetch var Children = { diff --git a/compiled/facebook-www/ReactServer-prod.modern.js b/compiled/facebook-www/ReactServer-prod.modern.js index 8405e85cf76e0..b2161e1d11109 100644 --- a/compiled/facebook-www/ReactServer-prod.modern.js +++ b/compiled/facebook-www/ReactServer-prod.modern.js @@ -72,9 +72,7 @@ function ReactElement(type, key, _ref, self, source, owner, props) { }; } function jsxProd(type, config, maybeKey) { - var propName, - props = {}, - key = null, + var key = null, ref = null; void 0 !== maybeKey && (key = "" + maybeKey); void 0 !== config.key && (key = "" + config.key); @@ -82,20 +80,24 @@ function jsxProd(type, config, maybeKey) { enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, ReactCurrentOwner.current, type))); - for (propName in config) + maybeKey = {}; + for (var propName in config) hasOwnProperty.call(config, propName) && "key" !== propName && (enableRefAsProp || "ref" !== propName) && (enableRefAsProp && "ref" === propName - ? (props.ref = coerceStringRef( + ? (maybeKey.ref = coerceStringRef( config[propName], ReactCurrentOwner.current, type )) - : (props[propName] = config[propName])); - if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) - for (propName in ((config = type.defaultProps), config)) - void 0 === props[propName] && (props[propName] = config[propName]); + : (maybeKey[propName] = config[propName])); + if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { + config = type.defaultProps; + for (var propName$0 in config) + void 0 === maybeKey[propName$0] && + (maybeKey[propName$0] = config[propName$0]); + } return ReactElement( type, key, @@ -103,7 +105,7 @@ function jsxProd(type, config, maybeKey) { void 0, void 0, ReactCurrentOwner.current, - props + maybeKey ); } function cloneAndReplaceKey(oldElement, newKey) { @@ -600,4 +602,4 @@ exports.useId = function () { exports.useMemo = function (create, deps) { return ReactCurrentDispatcher.current.useMemo(create, deps); }; -exports.version = "19.0.0-www-modern-d4f4a106"; +exports.version = "19.0.0-www-modern-ea5b7988";