diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 49968b33590d9..7dc940cfdd4ef 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -3276,6 +3276,7 @@ describe('ReactFlight', () => { expect(typeof loggedFn2).toBe('function'); expect(loggedFn2).not.toBe(foo); expect(loggedFn2.toString()).toBe(foo.toString()); + expect(loggedFn2).toBe(loggedFn); const promise = mockConsoleLog.mock.calls[0][1].promise; expect(promise).toBeInstanceOf(Promise); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index e51197c5b2b19..f40e3bd9deb66 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -4096,8 +4096,25 @@ function renderConsoleValue( } // Serialize the body of the function as an eval so it can be printed. - // $FlowFixMe[method-unbinding] - return serializeEval('(' + Function.prototype.toString.call(value) + ')'); + const writtenObjects = request.writtenObjects; + const existingReference = writtenObjects.get(value); + if (existingReference !== undefined) { + // We've already emitted this function, so we can + // just refer to that by its existing reference. + return existingReference; + } + + const serializedValue = serializeEval( + // $FlowFixMe[method-unbinding] + '(' + Function.prototype.toString.call(value) + ')', + ); + request.pendingChunks++; + const id = request.nextChunkId++; + const processedChunk = encodeReferenceChunk(request, id, serializedValue); + request.completedRegularChunks.push(processedChunk); + const reference = serializeByValueID(id); + writtenObjects.set(value, reference); + return reference; } if (typeof value === 'symbol') {