Skip to content

Commit

Permalink
Support Promise as a renderable node (#25634)
Browse files Browse the repository at this point in the history
Implements Promise as a valid React node types. The idea is that any
type that can be unwrapped with `use` should also be renderable.

When the reconciler encounters a Usable in a child position, it will
transparently unwrap the value before reconciling it. The value of the
inner value will determine the identity of the child during
reconciliation, not the Usable object that wraps around it.

Unlike `use`, the reconciler will recursively unwrap the value until it
reaches a non-Usable type, e.g. `Usable<Usable<Usable<T>>>` will resolve
to T.

In this initial commit, I've added support for Promises. I will do
Context in the [next
step](#25641).

Being able to render a promise as a child has several interesting
implications. The Server Components response format can use this feature
in its implementation — instead of wrapping references to client
components in `React.lazy`, it can just use a promise.

This also fulfills one of the requirements for async components on the
client, because an async component always returns a promise for a React
node. However, we will likely warn and/or lint against this for the time
being because there are major caveats if you re-render an async
component in response to user input. (Note: async components already
work in a Server Components environment — the caveats only apply to
running them in the browser.)

To suspend, React uses the same algorithm as `use`: by throwing an
exception to unwind the stack, then replaying the begin phase once the
promise resolves. It's a little weird to suspend during reconciliation,
however, `lazy` already does this so if there were any obvious bugs
related to that we likely would have already found them.

Still, the structure is a bit unfortunate. Ideally, we shouldn't need to
replay the entire begin phase of the parent fiber in order to reconcile
the children again. This would require a somewhat significant refactor,
because reconciliation happens deep within the begin phase, and
depending on the type of work, not always at the end. We should consider
as a future improvement.

DiffTrain build for [d4f58c3](d4f58c3)
  • Loading branch information
acdlite committed Mar 11, 2023
1 parent 1dd9e4e commit 132204a
Show file tree
Hide file tree
Showing 25 changed files with 3,225 additions and 1,957 deletions.
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
93c10dfa6b0848c12189b773b59c77d74cad2a1a
d4f58c3b8123f1654ca1b06692c3165928bef8df
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ if (
}
"use strict";

var ReactVersion = "18.3.0-www-modern-f87ae691";
var ReactVersion = "18.3.0-www-modern-abf2779e";

// ATTENTION
// When adding new symbols to this file,
Expand Down
Loading

0 comments on commit 132204a

Please sign in to comment.