-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Add React.Suspense component, remove React.useMutationEffect hook #7213
Conversation
The type-at-pos test kept crashing for me locally but I don't think that's related to this PR. |
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.
@jbrown215 has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
@@ -250,6 +250,12 @@ declare module react { | |||
declare export var ConcurrentMode: ({children: ?React$Node}) => React$Node; // 16.7+ | |||
declare export var StrictMode: ({children: ?React$Node}) => React$Node; |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
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.
Good catch. I'm ok with adding that fix to this PR or doing it in a separate 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.
@bvaughn actually brought up a good point below, it's not quite a ComponentType. It will be an AbstractComponent, though!
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.
Let's leave it for now?
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, sounds good
lib/react.js
Outdated
@@ -250,6 +250,12 @@ declare module react { | |||
declare export var ConcurrentMode: ({children: ?React$Node}) => React$Node; // 16.7+ | |||
declare export var StrictMode: ({children: ?React$Node}) => React$Node; | |||
|
|||
declare export var Suspense: React$ComponentType<{ | |||
children?: ?React$Node, | |||
fallback: React$Node, |
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.
fallback is optional (for nested Suspense components); missing, undefined, and null should all typecheck I think
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.
Ah thanks! I thought it was a required prop.
children?: ?React$Node, | ||
fallback: React$Node, | ||
maxDuration?: number | ||
}>; // 16.6+ |
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.
Does this imply that this is a class? I guess that isn't technically correct since it's one of those internal special symbols like Fragment but maybe good enough for now.
Should it use the same hack as Fragments and pretend to be a functional component? That way maybe refs are invalid maybe?
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.
Should it use the same hack as Fragments and pretend to be a functional component? That way maybe refs are invalid maybe?
Then people might think they can call it as a function, which would error? (Doesn't seem like that would obviously be better than this.)
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.
ComponentType is the type alias that (currently) represents function components and class components.
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.
Is there an alias for something that more accurately represents StrictMode
, Suspense
, etc?
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.
Not yet, but AbstractComponent will fulfill that role!
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.
Then people might think they can call it as a function, which would error? (Doesn't seem like that would obviously be better than this.)
If the instance type is void, it's more precise to use the function hack. Since we're already using that hack today, and since it will be fixed as part of my work on AbstractComponent, I think we should use the function representation for now.
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.
Ok~
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.
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.
Calling Suspense
directly (as a plain function) e.g. Suspense({ maxDuration: 'abc' })
properly catches the error, but wrapping it in a createElement
call e.g. <Suspense maxDuration="abc" />
does not.
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.
Fragment
seems similarly broken? Shouldn't this fail?
@@ -250,6 +250,12 @@ declare module react { | |||
declare export var ConcurrentMode: ({children: ?React$Node}) => React$Node; // 16.7+ | |||
declare export var StrictMode: ({children: ?React$Node}) => React$Node; | |||
|
|||
declare export var Suspense: React$ComponentType<{ | |||
children?: ?React$Node, |
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.
Is this needed?
IIUC, this says that it may or may not have children, and they have to be react nodes. I think that's the default.
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.
whoa, that seems like a bug – composite components should only take children if it's explicitly specified (it's only host components like 'div'
that always take React$Node children)
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.
Based on the context Provider
and Consumer
types above, I assumed an explicit children
prop was needed.
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.
FWIW, children is the part of our react model that I'm still not totally familiar with. I'm glad we're having this conversation because it's forcing me to look into it more.
@sophiebits: I'll have to do some more investigation. Requiring an explicit children prop would be an extremely disruptive change at this point.
@bvaughn: I just took a look at our react docs to see what we say about children types. It looks like we have conflicting advice here and here. I think the ?React.Node
bit is necessary, but I'm unclear about whether or not the ?children
part is also necessary. I'll have to look into it more, but either way I'm ok with what you have here.
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.
@sophiebits: Width subtyping allows extra properties to be passed into an object, so if the Props type is not exact then we allow children even if they are not specified explicitly. On the other hand, if the Props type is exact then we don't allow the extra properties.
Mystery solved!
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.
for posterity: React's treatment of children
:
- React.createElement takes varargs that become
props.children
(JSX children syntax turns into this) - host component (
'div'
etc)children
prop needs to be react nodes and React recurses into them - composite component
children
are not special in any way; by convention people often use it to contain React nodes then render<div>{props.children}</div>
or similar, but they can also be other data types (eg: the "render props" pattern often haschildren
be a function)
I pushed a change to make |
Yea, that looks like a bug to me. The only downside I see with ComponentType is that we won't correctly check the AbstractComponent is far enough along that I don't think this problem will be around for long. |
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.
@jbrown215 has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
Sweet! Thanks for the udpate! |
@bvaughn: I think the tests need to be re-recorded again. |
Yeah, I noticed. I guess something landed in master that caused conflicts. I'm in the process of rebasing and rerecording now. |
I noticed something wrong with the |
Okay. I think I fixed the bad Edit not sure why CI is failing:
|
Okay. |
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.
@jbrown215 has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
Can useRef current be not nullable since it has default value? |
The default value isn't required :(. This is something Brian and I did discuss too |
FB internal lint failure because of the lack of a newline at the end of the |
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.
@bvaughn has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
Summary: Resolves #7219 - [x] 2fdcda5: Removed `React.useMutationEffect` hook (facebook/react/pull/14336) and updated tests. This hook was only ever exposed in an alpha release of 16.7 and so it should be safe to remove in a non-backwards-compatible way. - [x] dabf49e: Add `React.Suspense` component and tests. (No final public documentation exists for `Suspense` yet– although we're working on it. For the time being, [tests like this](https://github.com/facebook/react/blob/master/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js) can serve as a reference.) - [x] 8df05bd: Fixed invalid `useCallback` definition and tests. - [x] 063b022: Fixed invalid `React.lazy` signature to reflect that a `Promise` with a "default" property should be returned (rather than a React component). Pull Request resolved: #7213 Reviewed By: jbrown215 Differential Revision: D13222880 Pulled By: bvaughn fbshipit-source-id: 9e1b48ace984051928c4ab92fa61182ad70f7119
Resolves #7219
React.useMutationEffect
hook (Remove useMutationEffect react#14336) and updated tests. This hook was only ever exposed in an alpha release of 16.7 and so it should be safe to remove in a non-backwards-compatible way.React.Suspense
component and tests. (No final public documentation exists forSuspense
yet– although we're working on it. For the time being, tests like this can serve as a reference.)useCallback
definition and tests.React.lazy
signature to reflect that aPromise
with a "default" property should be returned (rather than a React component).