Skip to content

Commit

Permalink
Rename the react.element symbol to react.transitional.element
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Apr 10, 2024
1 parent a8a83f7 commit 8549a5d
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 6 deletions.
5 changes: 3 additions & 2 deletions packages/react-devtools-shared/src/backend/ReactSymbols.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ export const SERVER_CONTEXT_SYMBOL_STRING = 'Symbol(react.server_context)';

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

export const ELEMENT_NUMBER = 0xeac7;
export const ELEMENT_SYMBOL_STRING = 'Symbol(react.element)';
export const ELEMENT_SYMBOL_STRING = 'Symbol(react.transitional.element)';
export const LEGACY_ELEMENT_NUMBER = 0xeac7;
export const LEGACY_ELEMENT_SYMBOL_STRING = 'Symbol(react.element)';

export const DEBUG_TRACING_MODE_NUMBER = 0xeae1;
export const DEBUG_TRACING_MODE_SYMBOL_STRING =
Expand Down
25 changes: 25 additions & 0 deletions packages/react-dom/src/__tests__/ReactComponent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,31 @@ describe('ReactComponent', () => {
);
});

it('throws if a legacy element is used as a child', async () => {
const inlinedElement = {
$$typeof: Symbol.for('react.element'),
type: 'div',
key: null,
ref: null,
props: {},
_owner: null,
};
const element = <div>{[inlinedElement]}</div>;
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(
act(() => {
root.render(element);
}),
).rejects.toThrowError(
'A React Element from an older version of React was rendered. ' +
'This is not supported. It can happen if:\n' +
'- Multiple copies of the "react" package is used.\n' +
'- A library pre-bundled an old copy of "react" or "react/jsx-runtime".\n' +
'- A compiler tries to "inline" JSX instead of using the runtime.',
);
});

it('throws if a plain object even if it is in an owner', async () => {
class Foo extends React.Component {
render() {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-dom/src/__tests__/ReactDOMOption-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ describe('ReactDOMOption', () => {
// This is similar to <fbt>.
// We don't toString it because you must instead provide a value prop.
const obj = {
$$typeof: Symbol.for('react.element'),
$$typeof: Symbol.for('react.transitional.element'),
type: props => props.content,
ref: null,
key: null,
Expand Down
2 changes: 1 addition & 1 deletion packages/react-dom/src/__tests__/refs-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ describe('ref swapping', () => {
await expect(async () => {
await act(() => {
root.render({
$$typeof: Symbol.for('react.element'),
$$typeof: Symbol.for('react.transitional.element'),
type: 'div',
props: {
ref: undefined,
Expand Down
11 changes: 11 additions & 0 deletions packages/react-reconciler/src/ReactChildFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
REACT_PORTAL_TYPE,
REACT_LAZY_TYPE,
REACT_CONTEXT_TYPE,
REACT_LEGACY_ELEMENT_TYPE,
} from 'shared/ReactSymbols';
import {HostRoot, HostText, HostPortal, Fragment} from './ReactWorkTags';
import isArray from 'shared/isArray';
Expand Down Expand Up @@ -160,6 +161,16 @@ function coerceRef(
}

function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) {
if (newChild.$$typeof === REACT_LEGACY_ELEMENT_TYPE) {
throw new Error(
'A React Element from an older version of React was rendered. ' +
'This is not supported. It can happen if:\n' +
'- Multiple copies of the "react" package is used.\n' +
'- A library pre-bundled an old copy of "react" or "react/jsx-runtime".\n' +
'- A compiler tries to "inline" JSX instead of using the runtime.',
);
}

// $FlowFixMe[method-unbinding]
const childString = Object.prototype.toString.call(newChild);

Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/jsx/ReactJSXElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function elementRefGetterWithDeprecationWarning() {
/**
* Factory method to create a new React element. This no longer adheres to
* the class pattern, so do not use new to call it. Also, instanceof check
* will not work. Instead test $$typeof field against Symbol.for('react.element') to check
* will not work. Instead test $$typeof field against Symbol.for('react.transitional.element') to check
* if something is a React Element.
*
* @param {*} type
Expand Down
5 changes: 4 additions & 1 deletion packages/shared/ReactSymbols.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'

// The Symbol used to tag the ReactElement-like types.
export const REACT_ELEMENT_TYPE: symbol = Symbol.for('react.element');
export const REACT_ELEMENT_TYPE: symbol = Symbol.for(
'react.transitional.element',
);
export const REACT_LEGACY_ELEMENT_TYPE: symbol = Symbol.for('react.element');
export const REACT_PORTAL_TYPE: symbol = Symbol.for('react.portal');
export const REACT_FRAGMENT_TYPE: symbol = Symbol.for('react.fragment');
export const REACT_STRICT_MODE_TYPE: symbol = Symbol.for('react.strict_mode');
Expand Down

0 comments on commit 8549a5d

Please sign in to comment.