From 00540974b4d8d48c26d39e872b77635b74bed54c Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 6 Feb 2024 12:41:30 -0500 Subject: [PATCH] jsx(): Treat __self and __source as normal props These used to be reserved props because the classic React.createElement runtime passed this data as props, whereas the jsxDEV() runtime passes them as separate arguments. This brings us incrementally closer to being able to pass the props object directly through to React instead of cloning a subset into a new object. The React.createElement runtime is unaffected. --- packages/react/src/ReactElementProd.js | 16 ++++++++++++-- .../ReactElementValidator-test.internal.js | 22 +++++++++++++++++++ packages/react/src/jsx/ReactJSXElement.js | 12 ++++------ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/packages/react/src/ReactElementProd.js b/packages/react/src/ReactElementProd.js index 88b87a6dfb651..b4f1519c79786 100644 --- a/packages/react/src/ReactElementProd.js +++ b/packages/react/src/ReactElementProd.js @@ -232,8 +232,14 @@ export function createElement(type, config, children) { hasOwnProperty.call(config, propName) && // Skip over reserved prop names propName !== 'key' && - // TODO: These will no longer be reserved in the next major + // TODO: `ref` will no longer be reserved in the next major propName !== 'ref' && + // ...and maybe these, too, though we currently rely on them for + // warnings and debug information in dev. Need to decide if we're OK + // with dropping them. In the jsx() runtime it's not an issue because + // the data gets passed as separate arguments instead of props, but + // it would be nice to stop relying on them entirely so we can drop + // them from the internal Fiber field. propName !== '__self' && propName !== '__source' ) { @@ -375,8 +381,14 @@ export function cloneElement(element, config, children) { hasOwnProperty.call(config, propName) && // Skip over reserved prop names propName !== 'key' && - // TODO: These will no longer be reserved in the next major + // TODO: `ref` will no longer be reserved in the next major propName !== 'ref' && + // ...and maybe these, too, though we currently rely on them for + // warnings and debug information in dev. Need to decide if we're OK + // with dropping them. In the jsx() runtime it's not an issue because + // the data gets passed as separate arguments instead of props, but + // it would be nice to stop relying on them entirely so we can drop + // them from the internal Fiber field. propName !== '__self' && propName !== '__source' ) { diff --git a/packages/react/src/__tests__/ReactElementValidator-test.internal.js b/packages/react/src/__tests__/ReactElementValidator-test.internal.js index cd1259de19c02..c32ddd3b3fcbd 100644 --- a/packages/react/src/__tests__/ReactElementValidator-test.internal.js +++ b/packages/react/src/__tests__/ReactElementValidator-test.internal.js @@ -569,4 +569,26 @@ describe('ReactElementValidator', () => { React.createElement(Lazy); expect(didCall).toBe(false); }); + + it('__self and __source are treated as normal props', async () => { + // These used to be reserved props because the classic React.createElement + // runtime passed this data as props, whereas the jsxDEV() runtime passes + // them as separate arguments. + function Child({__self, __source}) { + return __self + __source; + } + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + // NOTE: The Babel transform treats the presence of these props as a syntax + // error but theoretically it doesn't have to. Using spread here to + // circumvent the syntax error and demonstrate that the runtime + // doesn't care. + const props = { + __self: 'Hello ', + __source: 'world!', + }; + await act(() => root.render()); + expect(container.textContent).toBe('Hello world!'); + }); }); diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js index 849d2e1604db0..bc3691e4a9d1b 100644 --- a/packages/react/src/jsx/ReactJSXElement.js +++ b/packages/react/src/jsx/ReactJSXElement.js @@ -239,10 +239,8 @@ export function jsx(type, config, maybeKey) { hasOwnProperty.call(config, propName) && // Skip over reserved prop names propName !== 'key' && - // TODO: These will no longer be reserved in the next major - propName !== 'ref' && - propName !== '__self' && - propName !== '__source' + // TODO: `ref` will no longer be reserved in the next major + propName !== 'ref' ) { props[propName] = config[propName]; } @@ -316,10 +314,8 @@ export function jsxDEV(type, config, maybeKey, source, self) { hasOwnProperty.call(config, propName) && // Skip over reserved prop names propName !== 'key' && - // TODO: These will no longer be reserved in the next major - propName !== 'ref' && - propName !== '__self' && - propName !== '__source' + // TODO: `ref` will no longer be reserved in the next major + propName !== 'ref' ) { props[propName] = config[propName]; }