Skip to content

Commit bd62a21

Browse files
committed
Rename the react.element symbol to react.transitional.element
1 parent a8a83f7 commit bd62a21

File tree

9 files changed

+309
-225
lines changed

9 files changed

+309
-225
lines changed

packages/react-devtools-shared/src/backend/ReactSymbols.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ export const SERVER_CONTEXT_SYMBOL_STRING = 'Symbol(react.server_context)';
2323

2424
export const DEPRECATED_ASYNC_MODE_SYMBOL_STRING = 'Symbol(react.async_mode)';
2525

26-
export const ELEMENT_NUMBER = 0xeac7;
27-
export const ELEMENT_SYMBOL_STRING = 'Symbol(react.element)';
26+
export const ELEMENT_SYMBOL_STRING = 'Symbol(react.transitional.element)';
27+
export const LEGACY_ELEMENT_NUMBER = 0xeac7;
28+
export const LEGACY_ELEMENT_SYMBOL_STRING = 'Symbol(react.element)';
2829

2930
export const DEBUG_TRACING_MODE_NUMBER = 0xeae1;
3031
export const DEBUG_TRACING_MODE_SYMBOL_STRING =

packages/react-dom/src/__tests__/ReactComponent-test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,31 @@ describe('ReactComponent', () => {
563563
);
564564
});
565565

566+
it('throws if a legacy element is used as a child', async () => {
567+
const inlinedElement = {
568+
$$typeof: Symbol.for('react.element'),
569+
type: 'div',
570+
key: null,
571+
ref: null,
572+
props: {},
573+
_owner: null,
574+
};
575+
const element = <div>{[inlinedElement]}</div>;
576+
const container = document.createElement('div');
577+
const root = ReactDOMClient.createRoot(container);
578+
await expect(
579+
act(() => {
580+
root.render(element);
581+
}),
582+
).rejects.toThrowError(
583+
'A React Element from an older version of React was rendered. ' +
584+
'This is not supported. It can happen if:\n' +
585+
'- Multiple copies of the "react" package is used.\n' +
586+
'- A library pre-bundled an old copy of "react" or "react/jsx-runtime".\n' +
587+
'- A compiler tries to "inline" JSX instead of using the runtime.',
588+
);
589+
});
590+
566591
it('throws if a plain object even if it is in an owner', async () => {
567592
class Foo extends React.Component {
568593
render() {

packages/react-dom/src/__tests__/ReactDOMOption-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ describe('ReactDOMOption', () => {
138138
// This is similar to <fbt>.
139139
// We don't toString it because you must instead provide a value prop.
140140
const obj = {
141-
$$typeof: Symbol.for('react.element'),
141+
$$typeof: Symbol.for('react.transitional.element'),
142142
type: props => props.content,
143143
ref: null,
144144
key: null,

packages/react-dom/src/__tests__/refs-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ describe('ref swapping', () => {
389389
await expect(async () => {
390390
await act(() => {
391391
root.render({
392-
$$typeof: Symbol.for('react.element'),
392+
$$typeof: Symbol.for('react.transitional.element'),
393393
type: 'div',
394394
props: {
395395
ref: undefined,

packages/react-reconciler/src/ReactChildFiber.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
REACT_PORTAL_TYPE,
3333
REACT_LAZY_TYPE,
3434
REACT_CONTEXT_TYPE,
35+
REACT_LEGACY_ELEMENT_TYPE,
3536
} from 'shared/ReactSymbols';
3637
import {HostRoot, HostText, HostPortal, Fragment} from './ReactWorkTags';
3738
import isArray from 'shared/isArray';
@@ -160,6 +161,16 @@ function coerceRef(
160161
}
161162

162163
function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) {
164+
if (newChild.$$typeof === REACT_LEGACY_ELEMENT_TYPE) {
165+
throw new Error(
166+
'A React Element from an older version of React was rendered. ' +
167+
'This is not supported. It can happen if:\n' +
168+
'- Multiple copies of the "react" package is used.\n' +
169+
'- A library pre-bundled an old copy of "react" or "react/jsx-runtime".\n' +
170+
'- A compiler tries to "inline" JSX instead of using the runtime.',
171+
);
172+
}
173+
163174
// $FlowFixMe[method-unbinding]
164175
const childString = Object.prototype.toString.call(newChild);
165176

packages/react/src/jsx/ReactJSXElement.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ function elementRefGetterWithDeprecationWarning() {
162162
/**
163163
* Factory method to create a new React element. This no longer adheres to
164164
* the class pattern, so do not use new to call it. Also, instanceof check
165-
* will not work. Instead test $$typeof field against Symbol.for('react.element') to check
165+
* will not work. Instead test $$typeof field against Symbol.for('react.transitional.element') to check
166166
* if something is a React Element.
167167
*
168168
* @param {*} type

packages/shared/ReactSymbols.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
1313

1414
// The Symbol used to tag the ReactElement-like types.
15-
export const REACT_ELEMENT_TYPE: symbol = Symbol.for('react.element');
15+
export const REACT_ELEMENT_TYPE: symbol = Symbol.for(
16+
'react.transitional.element',
17+
);
18+
export const REACT_LEGACY_ELEMENT_TYPE: symbol = Symbol.for('react.element');
1619
export const REACT_PORTAL_TYPE: symbol = Symbol.for('react.portal');
1720
export const REACT_FRAGMENT_TYPE: symbol = Symbol.for('react.fragment');
1821
export const REACT_STRICT_MODE_TYPE: symbol = Symbol.for('react.strict_mode');

0 commit comments

Comments
 (0)