-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support sync thenables for lazy() #14626
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we should do this but let's avoid the redundant commit
</Suspense>, | ||
); | ||
|
||
expect(ReactTestRenderer).toHaveYielded(['Loading...', 'Hi']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect(ReactTestRenderer).toHaveYielded(['Loading...', 'Hi']); | |
expect(ReactTestRenderer).toHaveYielded(['Hi']); |
lazyComponent._result = thenable; | ||
// Don't race with a sync thenable | ||
if (lazyComponent._status === Pending) { | ||
lazyComponent._result = thenable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alt suggestion:
// Check if it resolved synchronously
if (lazyComponent._status === Resolved) {
return lazyComponent._result;
}
Since if it's already resolved we don't need to throw the thenable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aaaah. That's why it had the loading state. Thanks.
@@ -47,6 +47,7 @@ export function readLazyComponentType<T>(lazyComponent: LazyComponent<T>): T { | |||
lazyComponent._status = Pending; | |||
const ctor = lazyComponent._ctor; | |||
const thenable = ctor(); | |||
lazyComponent._result = thenable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still needed because we read thenable from lazyComponent._result
while it's pending. If we keep the assignment, it will overwrite sync thenables. But if we remove it at all, we will throw null
instead of thenable. This fixes both cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You still need the assignment, but I don't think you need to move it up here. If you keep it right after the early return branch you added on line 78-80, then there's always a single assignment.
if (lazyComponent._status === Resolved) {
return lazyComponent._result;
}
lazyComponent._result = thenable;
throw thenable;
// Check if it resolved synchronously | ||
if (lazyComponent._status === Resolved) { | ||
return lazyComponent._result; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also do the same for failure. But doesn't seem worth the extra code to me. Could be a recursive call but then there's more risk of messing it up and going into a stack overflow. Meh.
I'll merge since this follows your suggestion. |
* Support sync thenables for lazy() * Don't commit twice
Does this make lazy() work in SSR? |
No, |
* Support sync thenables for lazy() * Don't commit twice
When will it be supported for ssr? |
Why don't we? Currently they fail with a confusing error because of a race condition (status gets set to resolved but then the result gets overwritten by the next line). This should fix it.
I figured this might be useful for testing. See enzymejs/enzyme#1917 (comment). It's awkward that people look for workarounds like
waitForLazyLoaded
in a synchronous environment. Supporting sync thenables could be a nice solution to that.