diff --git a/packages/react-transport-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js b/packages/react-transport-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js index 73c75872c506c..1aa02e00d54b5 100644 --- a/packages/react-transport-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js +++ b/packages/react-transport-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js @@ -71,6 +71,8 @@ export function processErrorChunk( ]; } +const hasOwnProperty = Object.prototype.hasOwnProperty; + function convertModelToJSON( request: Request, parent: {+[key: string]: ReactModel} | $ReadOnlyArray, @@ -88,12 +90,14 @@ function convertModelToJSON( } else { const jsonObj: {[key: string]: JSONValue} = {}; for (const nextKey in json) { - jsonObj[nextKey] = convertModelToJSON( - request, - json, - nextKey, - json[nextKey], - ); + if (hasOwnProperty.call(json, nextKey)) { + jsonObj[nextKey] = convertModelToJSON( + request, + json, + nextKey, + json[nextKey], + ); + } } return jsonObj; } diff --git a/packages/react-transport-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js b/packages/react-transport-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js index fd0d327fc8e68..1bdb8b7684b83 100644 --- a/packages/react-transport-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js +++ b/packages/react-transport-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js @@ -214,4 +214,23 @@ describe('ReactFlightDOMRelay', () => { const model = readThrough(transport); expect(model).toEqual(14); }); + + it('should warn in DEV if a class instance polyfill is passed to a host component', () => { + function Bar() {} + + function Foo() {} + Foo.prototype = Object.create(Bar.prototype); + // This is enumerable which some polyfills do. + Foo.prototype.constructor = Foo; + Foo.prototype.method = function() {}; + + expect(() => { + const transport = []; + ReactDOMFlightRelayServer.render(, transport); + readThrough(transport); + }).toErrorDev( + 'Only plain objects can be passed to client components from server components. ', + {withoutStack: true}, + ); + }); }); diff --git a/packages/react-transport-native-relay/src/ReactFlightNativeRelayServerHostConfig.js b/packages/react-transport-native-relay/src/ReactFlightNativeRelayServerHostConfig.js index 7ba6ba34420e8..ecea013654f39 100644 --- a/packages/react-transport-native-relay/src/ReactFlightNativeRelayServerHostConfig.js +++ b/packages/react-transport-native-relay/src/ReactFlightNativeRelayServerHostConfig.js @@ -71,6 +71,8 @@ export function processErrorChunk( ]; } +const hasOwnProperty = Object.prototype.hasOwnProperty; + function convertModelToJSON( request: Request, parent: {+[key: string]: ReactModel} | $ReadOnlyArray, @@ -88,12 +90,14 @@ function convertModelToJSON( } else { const jsonObj: {[key: string]: JSONValue} = {}; for (const nextKey in json) { - jsonObj[nextKey] = convertModelToJSON( - request, - json, - nextKey, - json[nextKey], - ); + if (hasOwnProperty.call(json, nextKey)) { + jsonObj[nextKey] = convertModelToJSON( + request, + json, + nextKey, + json[nextKey], + ); + } } return jsonObj; } diff --git a/packages/react-transport-native-relay/src/__tests__/ReactFlightNativeRelay-test.internal.js b/packages/react-transport-native-relay/src/__tests__/ReactFlightNativeRelay-test.internal.js index cf893bca760e6..a28a6fa35e078 100644 --- a/packages/react-transport-native-relay/src/__tests__/ReactFlightNativeRelay-test.internal.js +++ b/packages/react-transport-native-relay/src/__tests__/ReactFlightNativeRelay-test.internal.js @@ -105,4 +105,26 @@ describe('ReactFlightNativeRelay', () => { nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(), ).toMatchSnapshot(); }); + + it('should warn in DEV if a class instance polyfill is passed to a host component', () => { + function Bar() {} + + function Foo() {} + Foo.prototype = Object.create(Bar.prototype); + // This is enumerable which some polyfills do. + Foo.prototype.constructor = Foo; + Foo.prototype.method = function() {}; + + expect(() => { + const transport = []; + ReactNativeFlightRelayServer.render( + , + transport, + ); + readThrough(transport); + }).toErrorDev( + 'Only plain objects can be passed to client components from server components. ', + {withoutStack: true}, + ); + }); });