[Flight] Error if a legacy React Element is attempted to be rendered (#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.
Sebastian Markbåge committed
May 10, 2024 at 09:37 UTC
9d76c954cfe134d7f541c3e706e344e6845ba235
2 files changed
+38
packages/react-client/src/__tests__/ReactFlight-test.js
+28
@@ -938,6 +938,7 @@ describe('ReactFlight', () => {
938
});
939
});
940
941
+ // @gate renameElementSymbol
942
it('should emit descriptions of errors in dev', async () => {
943
const ClientErrorBoundary = clientReference(ErrorBoundary);
944
@@ -945,6 +946,21 @@ describe('ReactFlight', () => {
946
throw value;
947
}
948
949
+ function RenderInlined() {
950
+ const inlinedElement = {
951
+ $$typeof: Symbol.for('react.element'),
952
+ type: () => {},
953
+ key: null,
954
+ ref: null,
955
+ props: {},
956
+ _owner: null,
957
+ };
958
+ return inlinedElement;
959
+ }
960
+
961
+ // We wrap in lazy to ensure the errors throws lazily.
962
+ const LazyInlined = React.lazy(async () => ({default: RenderInlined}));
963
+
964
const testCases = (
965
<>
966
<ClientErrorBoundary expectedMessage="This is a real Error.">
@@ -1010,6 +1026,18 @@ describe('ReactFlight', () => {
1026
<Throw value={['array']} />
1027
</div>
1028
</ClientErrorBoundary>
1029
+ <ClientErrorBoundary
1030
+ expectedMessage={
1031
+ 'A React Element from an older version of React was rendered. ' +
1032
+ 'This is not supported. It can happen if:\n' +
1033
+ '- Multiple copies of the "react" package is used.\n' +
1034
+ '- A library pre-bundled an old copy of "react" or "react/jsx-runtime".\n' +
1035
+ '- A compiler tries to "inline" JSX instead of using the runtime.'
1036
+ }>
1037
+ <div>
1038
+ <LazyInlined />
1039
+ </div>
1040
+ </ClientErrorBoundary>
1041
</>
1042
);
1043
packages/react-server/src/ReactFlightServer.js
+10
@@ -99,6 +99,7 @@ import {resolveOwner, setCurrentOwner} from './flight/ReactFlightCurrentOwner';
99
import {
100
getIteratorFn,
101
REACT_ELEMENT_TYPE,
102
+ REACT_LEGACY_ELEMENT_TYPE,
103
REACT_FORWARD_REF_TYPE,
104
REACT_FRAGMENT_TYPE,
105
REACT_LAZY_TYPE,
@@ -2004,6 +2005,15 @@ function renderModelDestructive(
2005
resolvedModel,
2006
);
2007
}
2008
+ case REACT_LEGACY_ELEMENT_TYPE: {
2009
+ throw new Error(
2010
+ 'A React Element from an older version of React was rendered. ' +
2011
+ 'This is not supported. It can happen if:\n' +
2012
+ '- Multiple copies of the "react" package is used.\n' +
2013
+ '- A library pre-bundled an old copy of "react" or "react/jsx-runtime".\n' +
2014
+ '- A compiler tries to "inline" JSX instead of using the runtime.',
2015
+ );
2016
+ }
2017
}
2018
2019
if (isClientReference(value)) {