Skip to content
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 Promise as a renderable node #25634

Merged
merged 2 commits into from
Mar 11, 2023
Merged

Commits on Mar 11, 2023

  1. ReactThenable-test -> ReactUse-test

    Just a rename. Scope of this test file has expanded.
    acdlite committed Mar 11, 2023
    Configuration menu
    Copy the full SHA
    dcf76cf View commit details
    Browse the repository at this point in the history
  2. Support Promise as a renderable node

    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.
    
    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.
    acdlite committed Mar 11, 2023
    Configuration menu
    Copy the full SHA
    610b9df View commit details
    Browse the repository at this point in the history