Skip to content

Commit

Permalink
[Flight] Error if a legacy React Element is attempted to be rendered (#…
Browse files Browse the repository at this point in the history
…29043)

This errors on the client normally but in the case the `type` is a
function - i.e. a Server Component - it wouldn't be transferred to error
on the client so you end up with a worse error message. So this just
implements the same check as ChildFiber.
  • Loading branch information
sebmarkbage committed May 10, 2024
1 parent 2c022b8 commit 9d76c95
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 0 deletions.
28 changes: 28 additions & 0 deletions packages/react-client/src/__tests__/ReactFlight-test.js
Expand Up @@ -938,13 +938,29 @@ describe('ReactFlight', () => {
});
});

// @gate renameElementSymbol
it('should emit descriptions of errors in dev', async () => {
const ClientErrorBoundary = clientReference(ErrorBoundary);

function Throw({value}) {
throw value;
}

function RenderInlined() {
const inlinedElement = {
$$typeof: Symbol.for('react.element'),
type: () => {},
key: null,
ref: null,
props: {},
_owner: null,
};
return inlinedElement;
}

// We wrap in lazy to ensure the errors throws lazily.
const LazyInlined = React.lazy(async () => ({default: RenderInlined}));

const testCases = (
<>
<ClientErrorBoundary expectedMessage="This is a real Error.">
Expand Down Expand Up @@ -1010,6 +1026,18 @@ describe('ReactFlight', () => {
<Throw value={['array']} />
</div>
</ClientErrorBoundary>
<ClientErrorBoundary
expectedMessage={
'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.'
}>
<div>
<LazyInlined />
</div>
</ClientErrorBoundary>
</>
);

Expand Down
10 changes: 10 additions & 0 deletions packages/react-server/src/ReactFlightServer.js
Expand Up @@ -99,6 +99,7 @@ import {resolveOwner, setCurrentOwner} from './flight/ReactFlightCurrentOwner';
import {
getIteratorFn,
REACT_ELEMENT_TYPE,
REACT_LEGACY_ELEMENT_TYPE,
REACT_FORWARD_REF_TYPE,
REACT_FRAGMENT_TYPE,
REACT_LAZY_TYPE,
Expand Down Expand Up @@ -2004,6 +2005,15 @@ function renderModelDestructive(
resolvedModel,
);
}
case 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.',
);
}
}

if (isClientReference(value)) {
Expand Down

0 comments on commit 9d76c95

Please sign in to comment.