@samitouri / QOS-React / commits / 91caa96e42

jsx(): Treat __self and __source as normal props (#28257)

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.

Andrew Clark committed Feb 6, 2024 at 20:03 UTC 91caa96e4261704d42333f5e02ba32d870379fc4
3 files changed +40 -10
packages/react/src/ReactElementProd.js
+14 -2
@@ -232,8 +232,14 @@ export function createElement(type, config, children) {
232 hasOwnProperty.call(config, propName) &&
233 // Skip over reserved prop names
234 propName !== 'key' &&
235 - // TODO: These will no longer be reserved in the next major
235 + // TODO: `ref` will no longer be reserved in the next major
236 propName !== 'ref' &&
237 + // ...and maybe these, too, though we currently rely on them for
238 + // warnings and debug information in dev. Need to decide if we're OK
239 + // with dropping them. In the jsx() runtime it's not an issue because
240 + // the data gets passed as separate arguments instead of props, but
241 + // it would be nice to stop relying on them entirely so we can drop
242 + // them from the internal Fiber field.
243 propName !== '__self' &&
244 propName !== '__source'
245 ) {
@@ -375,8 +381,14 @@ export function cloneElement(element, config, children) {
381 hasOwnProperty.call(config, propName) &&
382 // Skip over reserved prop names
383 propName !== 'key' &&
378 - // TODO: These will no longer be reserved in the next major
384 + // TODO: `ref` will no longer be reserved in the next major
385 propName !== 'ref' &&
386 + // ...and maybe these, too, though we currently rely on them for
387 + // warnings and debug information in dev. Need to decide if we're OK
388 + // with dropping them. In the jsx() runtime it's not an issue because
389 + // the data gets passed as separate arguments instead of props, but
390 + // it would be nice to stop relying on them entirely so we can drop
391 + // them from the internal Fiber field.
392 propName !== '__self' &&
393 propName !== '__source'
394 ) {
packages/react/src/__tests__/ReactElementValidator-test.internal.js
+22
@@ -569,4 +569,26 @@ describe('ReactElementValidator', () => {
569 React.createElement(Lazy);
570 expect(didCall).toBe(false);
571 });
572 +
573 + it('__self and __source are treated as normal props', async () => {
574 + // These used to be reserved props because the classic React.createElement
575 + // runtime passed this data as props, whereas the jsxDEV() runtime passes
576 + // them as separate arguments.
577 + function Child({__self, __source}) {
578 + return __self + __source;
579 + }
580 +
581 + const container = document.createElement('div');
582 + const root = ReactDOMClient.createRoot(container);
583 + // NOTE: The Babel transform treats the presence of these props as a syntax
584 + // error but theoretically it doesn't have to. Using spread here to
585 + // circumvent the syntax error and demonstrate that the runtime
586 + // doesn't care.
587 + const props = {
588 + __self: 'Hello ',
589 + __source: 'world!',
590 + };
591 + await act(() => root.render(<Child {...props} />));
592 + expect(container.textContent).toBe('Hello world!');
593 + });
594 });
packages/react/src/jsx/ReactJSXElement.js
+4 -8
@@ -239,10 +239,8 @@ export function jsx(type, config, maybeKey) {
239 hasOwnProperty.call(config, propName) &&
240 // Skip over reserved prop names
241 propName !== 'key' &&
242 - // TODO: These will no longer be reserved in the next major
243 - propName !== 'ref' &&
244 - propName !== '__self' &&
245 - propName !== '__source'
242 + // TODO: `ref` will no longer be reserved in the next major
243 + propName !== 'ref'
244 ) {
245 props[propName] = config[propName];
246 }
@@ -316,10 +314,8 @@ export function jsxDEV(type, config, maybeKey, source, self) {
314 hasOwnProperty.call(config, propName) &&
315 // Skip over reserved prop names
316 propName !== 'key' &&
319 - // TODO: These will no longer be reserved in the next major
320 - propName !== 'ref' &&
321 - propName !== '__self' &&
322 - propName !== '__source'
317 + // TODO: `ref` will no longer be reserved in the next major
318 + propName !== 'ref'
319 ) {
320 props[propName] = config[propName];
321 }