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]; }