diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
index 0838371bef92c..d6d85b96ce702 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
@@ -6340,6 +6340,63 @@ describe('ReactDOMFizzServer', () => {
expect(getVisibleChildren(container)).toEqual('Hi');
});
+ it('should correctly handle different promises in React.use() across lazy components', async () => {
+ let promise1;
+ let promise2;
+ let promiseLazy;
+
+ function Component1() {
+ promise1 ??= new Promise(r => setTimeout(() => r('value1'), 50));
+ const data = React.use(promise1);
+ return (
+
+ {data}
+
+
+ );
+ }
+
+ function Component2() {
+ promise2 ??= new Promise(r => setTimeout(() => r('value2'), 50));
+ const data = React.use(promise2);
+ return {data}
;
+ }
+
+ const Component2Lazy = React.lazy(async () => {
+ promiseLazy ??= new Promise(r => setTimeout(r, 50));
+ await promiseLazy;
+ return {default: Component2};
+ });
+
+ function App() {
+ return ;
+ }
+
+ await act(async () => {
+ const {pipe} = renderToPipeableStream();
+ pipe(writable);
+ });
+
+ // Wait for promise to resolve
+ await act(async () => {
+ await promise1;
+ });
+ await act(async () => {
+ await promiseLazy;
+ });
+ await act(async () => {
+ await promise2;
+ });
+
+ // Verify both components received the correct values
+ expect(getVisibleChildren(container)).toEqual(
+ ,
+ );
+ });
+
it('useActionState hydrates without a mismatch', async () => {
// This is testing an implementation detail: useActionState emits comment
// nodes into the SSR stream, so this checks that they are handled correctly
diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js
index 75267e0e4f00b..b0df51e0bba64 100644
--- a/packages/react-server/src/ReactFizzServer.js
+++ b/packages/react-server/src/ReactFizzServer.js
@@ -4153,7 +4153,10 @@ function renderNode(
// $FlowFixMe[method-unbinding]
if (typeof x.then === 'function') {
const wakeable: Wakeable = (x: any);
- const thenableState = getThenableStateAfterSuspending();
+ const thenableState =
+ thrownValue === SuspenseException
+ ? getThenableStateAfterSuspending()
+ : null;
const newTask = spawnNewSuspendedReplayTask(
request,
// $FlowFixMe: Refined.
@@ -4186,7 +4189,10 @@ function renderNode(
// performance but it can lead to stack overflows in extremely deep trees.
// We do have the ability to create a trampoile if this happens which makes
// this kind of zero-cost.
- const thenableState = getThenableStateAfterSuspending();
+ const thenableState =
+ thrownValue === SuspenseException
+ ? getThenableStateAfterSuspending()
+ : null;
const newTask = spawnNewSuspendedReplayTask(
request,
// $FlowFixMe: Refined.
@@ -4246,7 +4252,10 @@ function renderNode(
// $FlowFixMe[method-unbinding]
if (typeof x.then === 'function') {
const wakeable: Wakeable = (x: any);
- const thenableState = getThenableStateAfterSuspending();
+ const thenableState =
+ thrownValue === SuspenseException
+ ? getThenableStateAfterSuspending()
+ : null;
const newTask = spawnNewSuspendedRenderTask(
request,
// $FlowFixMe: Refined.
@@ -4317,7 +4326,10 @@ function renderNode(
// performance but it can lead to stack overflows in extremely deep trees.
// We do have the ability to create a trampoile if this happens which makes
// this kind of zero-cost.
- const thenableState = getThenableStateAfterSuspending();
+ const thenableState =
+ thrownValue === SuspenseException
+ ? getThenableStateAfterSuspending()
+ : null;
const newTask = spawnNewSuspendedRenderTask(
request,
// $FlowFixMe: Refined.
@@ -5233,7 +5245,10 @@ function retryRenderTask(
if (typeof x.then === 'function') {
// Something suspended again, let's pick it back up later.
segment.status = PENDING;
- task.thenableState = getThenableStateAfterSuspending();
+ task.thenableState =
+ thrownValue === SuspenseException
+ ? getThenableStateAfterSuspending()
+ : null;
const ping = task.ping;
// We've asserted that x is a thenable above
(x: any).then(ping, ping);
@@ -5338,7 +5353,10 @@ function retryReplayTask(request: Request, task: ReplayTask): void {
// Something suspended again, let's pick it back up later.
const ping = task.ping;
x.then(ping, ping);
- task.thenableState = getThenableStateAfterSuspending();
+ task.thenableState =
+ thrownValue === SuspenseException
+ ? getThenableStateAfterSuspending()
+ : null;
return;
}
}