Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a4329f4

Browse files
committedMar 10, 2022
add lazy initialization to resolveModelToJson
adding lazying initialization toResolveModelToJson means we use attemptResolveElement's full logic on whatever the resolved type ends up being. This better aligns handling of misued Lazy types like a lazy element being used as a Component or a lazy Component being used as an element.
1 parent 6b9c8c6 commit a4329f4

File tree

2 files changed

+77
-6
lines changed

2 files changed

+77
-6
lines changed
 

‎packages/react-client/src/__tests__/ReactFlight-test.js

+74
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,43 @@ describe('ReactFlight', () => {
184184
);
185185
});
186186

187+
it('errors on a Lazy element being used in Component position', async () => {
188+
function SharedComponent({text}) {
189+
return (
190+
<div>
191+
shared<span>{text}</span>
192+
</div>
193+
);
194+
}
195+
196+
let load = null;
197+
198+
const LazyElementDisguisedAsComponent = React.lazy(() => {
199+
return new Promise(res => {
200+
load = () => res({default: <SharedComponent text={'a'} />});
201+
});
202+
});
203+
204+
function ServerComponent() {
205+
return (
206+
<React.Suspense fallback={'Loading...'}>
207+
<LazyElementDisguisedAsComponent text={'b'} />
208+
</React.Suspense>
209+
);
210+
}
211+
212+
const transport = ReactNoopFlightServer.render(<ServerComponent />);
213+
214+
act(() => {
215+
const rootModel = ReactNoopFlightClient.read(transport);
216+
ReactNoop.render(rootModel);
217+
});
218+
expect(ReactNoop).toMatchRenderedOutput('Loading...');
219+
spyOnDevAndProd(console, 'error');
220+
await load();
221+
expect(console.error).toHaveBeenCalledTimes(1);
222+
});
223+
187224
it('can render a lazy element', async () => {
188225
function SharedComponent({text}) {
189226
return (
@@ -229,6 +266,43 @@ describe('ReactFlight', () => {
229266
);
230267
});
231268

269+
it('errors with lazy value in element position that resolves to Component', async () => {
270+
function SharedComponent({text}) {
271+
return (
272+
<div>
273+
shared<span>{text}</span>
274+
</div>
275+
);
276+
}
277+
278+
let load = null;
279+
280+
const componentDisguisedAsElement = React.lazy(() => {
281+
return new Promise(res => {
282+
load = () => res({default: SharedComponent});
283+
});
284+
});
285+
286+
function ServerComponent() {
287+
return (
288+
<React.Suspense fallback={'Loading...'}>
289+
{componentDisguisedAsElement}
290+
</React.Suspense>
291+
);
292+
}
293+
294+
const transport = ReactNoopFlightServer.render(<ServerComponent />);
295+
296+
act(() => {
297+
const rootModel = ReactNoopFlightClient.read(transport);
298+
ReactNoop.render(rootModel);
299+
});
300+
expect(ReactNoop).toMatchRenderedOutput('Loading...');
301+
spyOnDevAndProd(console, 'error');
302+
await load();
303+
expect(console.error).toHaveBeenCalledTimes(1);
304+
});
305+
232306
it('can render a lazy module reference', async () => {
233307
function ClientComponent() {
234308
return <div>I am client</div>;

‎packages/react-server/src/ReactFlightServer.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,6 @@ function attemptResolveElement(
210210
const render = type.render;
211211
return render(props, undefined);
212212
}
213-
case REACT_ELEMENT_TYPE: {
214-
// this can happen when a lazy component resolves to an element instead of
215-
// a Component.
216-
return attemptResolveElement(type.type, type.key, type.ref, type.props);
217-
}
218213
case REACT_MEMO_TYPE: {
219214
return attemptResolveElement(type.type, key, ref, props);
220215
}
@@ -508,7 +503,9 @@ export function resolveModelToJSON(
508503
break;
509504
}
510505
case REACT_LAZY_TYPE: {
511-
value = attemptResolveElement(value, null, null, {});
506+
const payload = (value: any)._payload;
507+
const init = (value: any)._init;
508+
value = init(payload);
512509
break;
513510
}
514511
}

0 commit comments

Comments
 (0)
Please sign in to comment.