-
Notifications
You must be signed in to change notification settings - Fork 48.1k
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
Capture suspense boundaries with undefined fallbacks #21702
Capture suspense boundaries with undefined fallbacks #21702
Conversation
} | ||
this.stack.push(frame); | ||
return ''; | ||
} |
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.
I could not find a test that exercises this block, not could I figure out how to create one.
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.
I'll make one. I had that on my TODO to test this parity.
@@ -1910,22 +1906,18 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) { | |||
if (current === null) { | |||
// Initial mount | |||
// If we're currently hydrating, try to hydrate this boundary. | |||
// But only if this has a fallback. |
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 change is reflected in the ReactDOMServerPartialHydration-test.internal.js test.
@@ -391,44 +391,10 @@ describe('ReactSuspense', () => { | |||
expect(root).toMatchRenderedOutput('Hi'); | |||
}); | |||
|
|||
it('only captures if `fallback` is defined', () => { |
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.
Moved to ReactSuspenseFallback-test.
Comparing: 43f4cc1...614f1c6 Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: Expand to show
|
packages/react-reconciler/src/__tests__/ReactSuspenseFallback-test.js
Outdated
Show resolved
Hide resolved
React = require('react'); | ||
ReactTestRenderer = require('react-test-renderer'); | ||
Scheduler = require('scheduler'); | ||
ReactCache = require('react-cache'); |
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.
Can you use the helpers in ReactSuspenseWithNoopRenderer-test or ReactCache-test instead? Those are the closest to our preferred testing idioms. We're going to remove the react-cache
package.
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.
Ideally just put them into those existing files. It tends to get annoying to update the helpers in different files that use the same patterns. For example we'll need to do a bunch of refactoring to change the avoidThisFallback API that needs to basically test all the same things again.
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.
I put them in separate files because @acdlite mentioned that we should break out more tests into separate files for speed and organizational reasons.
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.
In that case, maybe the helpers should be broken out into a shared module too.
Organizationally I find that what organization we thought would make sense in terms of grouping features doesn't hold up for the next change.
The defacto pattern that has evolved that is pretty convenient is that files are grouped by the kind of test mechanism. So you can find a test with similar mechanism that you need and then copy it. It doesn't help speed so the way we solved that for the ServerIntegration tests is that we broke them out into a shared helper and then pulled that in everywhere.
It would also be nice if we didn't mix test mechanisms in the same file.
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.
My main reason for suggesting more focused module was because some of them are getting really slow.
I've been resistant to the idea of having test helper modules because I don't want it to become a dumping ground for a bunch of idiosyncratic abstractions. I like that if there's a bad abstraction, it's confined to a single module.
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.
Really it's because I dislike when a test breaks and I have to open multiple files to figure out what the hell is going on, which is the case for some of our older server rendering tests
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.
The scheduler.yield things are a helper that is an example of doing it right so it can be done right.
I'm not a fan of the server rendering strategy per se but at least it's the same one every time. The ones that get really frustrating to upgrade from an older pattern are the ones using similar but slightly different patterns.
Who am I and what have I done to the good olde wet Seb?
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.
Ultimately this is kind of a flaw of jest. We reset modules between every run anyway. There's no reason we couldn't run every individual test case in a separate process. That would also let us use proper ES modules since it would by default reset modules.
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.
The ones that get really frustrating to upgrade from an older pattern are the ones using similar but slightly different patterns.
I agree with that but I suppose I don't mind because in aggregate we spend more time debugging tests than we do making API changes.
In this particular case, though, I think the "async text" pattern has solidified enough that I'd be comfortable moving it to its own helper, a la yieldValue
.
37e6874
to
b0c7eb3
Compare
b0c7eb3
to
614f1c6
Compare
Hey @rickhanlonii @acdlite Did you mean to merge this into |
Capture suspense boundaries with undefined fallbacks (facebook#21702)
He fixed it with #21854. I am curious how |
@zpao there may have been a failure when doing the rename. I can't tell now because we deleted the branch, but you can see how in this old screenshot of react-native after the rename that there was a "rename failed" next to |
Yeah, we later noticed that a lot of PRs failed to get renamed. I think the underlying cause has since been fixed (by Jon?) |
Overview
This PR updates the behavior of the Suspense component so that it when the fallback is missing we still capture the boundary and renders
null
for the fallback.Consider this code:
Previously, since the inner Suspense boundary did not provide a fallback, we silently skipped it and kept going to the "outer" boundary. This is hard to debug and can be confusing.
Instead, we're going to capture the inner boundary and render an empty placeholder. This should make it more obvious to the user that they forgot to provide the fallback, and allow supporting use cases where that's what you intend to do.