Repository: facebook/react
Pull request: Fix resolving of references to deduped props in lazy elements

When a model references a deduped object of a blocked element that has subsequently been turned into a lazy element, we need to wait for the lazy element's chunk to resolve before resolving the reference.

Without the fix, the new test failed with the following runtime error:

```
TypeError: Cannot read properties of undefined (reading 'children')
  1003 |       let value = chunk.value;
  1004 |       for (let i = 1; i < path.length; i++) {
> 1005 |         value = value[path[i]];
       |                          ^
  1006 |       }
  1007 |       const chunkValue = map(response, value);
  1008 |       if (__DEV__ && chunk._debugInfo) {

  at getOutlinedModel (packages/react-client/src/ReactFlightClient.js:1005:26)
```

The bug was uncovered after updating React in Next.js in https://github.com/vercel/next.js/pull/66711.

Changed files:
filename: packages/react-client/src/ReactFlightClient.js
patch: @@ -827,7 +827,7 @@ function getChunk(response: Response, id: number): SomeChunk<any> {
 }
 
 function waitForReference<T>(
-  referencedChunk: PendingChunk<T> | BlockedChunk<T>,
+  referencedChunk: SomeChunk<T>,
   parentObject: Object,
   key: string,
   response: Response,
@@ -1003,6 +1003,21 @@ function getOutlinedModel<T>(
       let value = chunk.value;
       for (let i = 1; i < path.length; i++) {
         value = value[path[i]];
+        if (value.$$typeof === REACT_LAZY_TYPE) {
+          const referencedChunk: SomeChunk<any> = value._payload;
+          if (referencedChunk.status === INITIALIZED) {
+            value = referencedChunk.value;
+          } else {
+            return waitForReference(
+              referencedChunk,
+              parentObject,
+              key,
+              response,
+              map,
+              path.slice(i),
+            );
+          }
+        }
       }
       const chunkValue = map(response, value);
       if (__DEV__ && chunk._debugInfo) {

filename: packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
patch: @@ -456,6 +456,75 @@ describe('ReactFlightDOMBrowser', () => {
     expect(container.innerHTML).toBe('{}');
   });
 
+  it('should resolve deduped objects in blocked models referencing other blocked models with blocked references', async () => {
+    let resolveFooClientComponentChunk;
+    let resolveBarClientComponentChunk;
+
+    function PassthroughServerComponent({children}) {
+      return children;
+    }
+
+    const FooClient = clientExports(
+      function FooClient({children}) {
+        return JSON.stringify(children);
+      },
+      '1',
+      '/foo.js',
+      new Promise(resolve => (resolveFooClientComponentChunk = resolve)),
+    );
+
+    const BarClient = clientExports(
+      function BarClient() {
+        return 'not used';
+      },
+      '2',
+      '/bar.js',
+      new Promise(resolve => (resolveBarClientComponentChunk = resolve)),
+    );
+
+    const shared = {foo: 1};
+
+    function Server() {
+      return (
+        <>
+          <PassthroughServerComponent>
+            <FooClient key="first" bar={BarClient}>
+              {shared}
+            </FooClient>
+          </PassthroughServerComponent>
+          <FooClient key="second" bar={BarClient}>
+            {shared}
+          </FooClient>
+        </>
+      );
+    }
+
+    const stream = await serverAct(() =>
+      ReactServerDOMServer.renderToReadableStream(<Server />, webpackMap),
+    );
+
+    function ClientRoot({response}) {
+      return use(response);
+    }
+
+    const response = ReactServerDOMClient.createFromReadableStream(stream);
+    const container = document.createElement('div');
+    const root = ReactDOMClient.createRoot(container);
+
+    await act(() => {
+      root.render(<ClientRoot response={response} />);
+    });
+
+    expect(container.innerHTML).toBe('');
+
+    await act(() => {
+      resolveFooClientComponentChunk();
+      resolveBarClientComponentChunk();
+    });
+
+    expect(container.innerHTML).toBe('{"foo":1}{"foo":1}');
+  });
+
   it('should progressively reveal server components', async () => {
     let reportedErrors = [];