Commit Graph

4738 Commits

Author SHA1 Message Date
Jan Kassens 18dedde6a7 [flow] upgrade to 0.206.0 (#26850)
Small upgrade. The one impact was deprecation of `$Shape` where it seems
like we can just use a plain object with optional key.
2023-05-25 13:37:31 -04:00
Ricky ee4233bdbc Move enableSyncDefaultUpdates to test config (#26847) 2023-05-24 18:25:30 -04:00
Yen-Wei Liu 535c038d15 Update preload links to support nonce and fetchpriority (#26826)
Currently when React generates rel=preload link tags for script/stylesheet resources, it will not carryover nonce and fetchpriority values if specified on the original elements.

This change ensures that the preload links use the nonce and fetchPriority values if they were specified.
2023-05-22 22:56:17 -04:00
Dennis Moradkhani 4b877b6c66 Updated copyright text to Copyright (c) Meta Platforms, Inc. and its … (#26830)
…affiliates.

## Summary

There were 8 different places where the copyright comment was wrong.
Rewrote from "Copyright (c) Facebook, Inc. and its affiliates." to
"Copyright (c) Meta Platforms, Inc. and its affiliates."

## How did you test this change?
No code was changed. Comment was still a comment after changes.

Co-authored-by: Dennis Moradkhani <denmo530@student.liu.se>
2023-05-19 17:52:17 -07:00
Sanket Singh 7bd330e0b0 Updated Copyright comment from Facebook to Meta (#26833)
## Summary
Changed the comment in react/packages/react
/react.shared-subset.js saying 
```
Copyright (c) Facebook, Inc. and affiliates ..
```
To 
```
Copyright (c) Meta Platforms, Inc. and affiliates ..
```
as raised in the following issues:
https://github.com/facebook/react/issues/26829

Files Changed: 
react/packages/react/react.shared-subset.js

## How did you test this change?

Tests Required: No
2023-05-19 17:51:44 -07:00
Sebastian Markbåge 5309f10285 Remove Flight Relay DOM/Native (#26828)
The bindings upstream in Relay has been removed so we don't need these
builds anymore. The idea is to revisit an FB integration of Flight but
it wouldn't use the Relay specific bindings. It's a bit unclear how it
would look but likely more like the OSS version so not worth keeping
these around.

The `dom-relay` name also included the FB specific Fizz implementation
of the streaming config so I renamed that to `dom-fb`. There's no Fizz
implementation for Native yet so I just removed `native-relay`.

We created a configurable fork for how to encode the output of Flight
and the Relay implementation encoded it as JSON objects instead of
strings/streams. The new implementation would likely be more stream-like
and just encode it directly as string/binary chunks. So I removed those
indirections so that this can just be declared inline in
ReactFlightServer/Client.
2023-05-17 20:33:25 -04:00
Ibrahem Mahyob d7a98a5e97 Fix strict mode badge URL (#26825)
## Summary
Closes https://github.com/facebook/react/issues/26821

[[Fix #26821]](https://github.com/facebook/react/issues/26821) Update
strict mode badge URL


Updated the URL in the strict mode badge to point to the correct React
documentation for StrictMode. The previous URL was outdated. Now, when a
component is not running in StrictMode, the badge links to
https://react.dev/reference/react/StrictMode for more information.


## How did you test this change?

I verified that the strict mode badge now correctly links to the updated
URL. Previously, it pointed to the outdated URL
(https://fb.me/devtools-strict-mode). After the update, it correctly
points to the React Dev documentation for StrictMode
(https://react.dev/reference/react/StrictMode).


_Since its my first contribution here, i have completed the CLA_
2023-05-17 13:34:34 +01:00
Ruslan Lesiutin 2468a87358 React DevTools 4.27.7 -> 4.27.8 (#26823)
Closes https://github.com/facebook/react/issues/26787,
https://github.com/facebook/react/issues/26793

Includes these changes:
* fix[devtools]: fixed duplicated backend activation with multiple
renderers ([hoxyq](https://github.com/hoxyq) in
[#26807](https://github.com/facebook/react/pull/26807))
2023-05-17 11:40:50 +01:00
Andrew Clark f8de255e94 Lower Suspense throttling heuristic to 300ms (#26803)
Now that the throttling mechanism applies more often, we've decided to
lower this a tad to ensure it's not noticeable. The idea is it should be
just large enough to prevent jank when lots of different parts of the UI
load in rapid succession, but not large enough to make the UI feel
sluggish. There's no perfect number, it's just a heuristic.
2023-05-16 15:59:15 -04:00
Andrew Clark 4bfcd02b2c Fix Suspense throttling mechanism (#26802)
The throttling mechanism for fallbacks should apply to both their
appearance _and_ disappearance.

This was mostly addressed by #26611. See that PR for additional context.

However, a flaw in the implementation is that we only update the the
timestamp used for throttling when the fallback initially appears. We
don't update it when the real content pops in. If lots of content in
separate Suspense trees loads around the same time, you can still get
jank.

The issue is fixed by updating the throttling timestamp whenever the
visibility of a fallback changes. Not just when it appears.
2023-05-16 15:03:30 -04:00
Sophie Alpert 4cd7065665 Fix uSES hydration in strict mode (#26791)
Previously, we'd call and use getSnapshot on the second render resulting
in `Warning: Text content did not match. Server: "Nay!" Client: "Yay!"`
and then `Error: Text content does not match server-rendered HTML.`.

Fixes #26095. Closes #26113. Closes #25650.

---------

Co-authored-by: eps1lon <silbermann.sebastian@gmail.com>
2023-05-12 14:18:03 -07:00
Ruslan Lesiutin 67a05d03e3 fix[devtools]: fixed duplicated backend activation with multiple renderers (#26807)
## Summary
Initially reported in https://github.com/facebook/react/issues/26797.
Was not able to reproduce the exact same problem, but found this case:

1. Open corresponding codepen from the issue in debug mode
2. Open components tab of the extension
3. Refresh the page

Received multiple errors:
- Warning in the Console tab: Invalid renderer id "2".
- Error in the Components tab: Uncaught Error: Cannot add node "3"
because a node with that id is already in the Store.

This problem has occurred after landing a fix in
https://github.com/facebook/react/pull/26779. Looks like Chrome is
keeping the injected scripts (the backend in this case) and we start
backend twice.
2023-05-12 14:59:53 +01:00
Jan Kassens df12d7eac4 [www] reduce dynamic SchedulerFeatureFlags (#26617)
For these values we're not using dynamic values. We can statically
compile in the values we're running.
2023-05-10 17:26:05 -04:00
Jan Kassens fda1f0b902 Flow upgrade to 0.205.1 (#26796)
Just a small upgrade to keep us current and remove unused suppressions
(probably fixed by some upgrade since).

- `*` is no longer allowed and has been an alias for `any` for a while
now.
2023-05-09 10:45:50 -04:00
Andrew Clark 16d053d592 Add useFormStatus to server rendering stub (#26788)
This was an oversight when I set up the hook in #26719.
2023-05-06 20:39:08 -04:00
Samuel Susla b00e27342d Use native scheduler if defined in global scope (#26554)
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2023-05-05 14:01:31 +01:00
Ruslan Lesiutin 783e7fcfa3 React DevTools 4.27.6 -> 4.27.7 (#26780)
List of changes:
* DevTools: fix backend activation ([hoxyq](https://github.com/hoxyq) in
[#26779](https://github.com/facebook/react/pull/26779))
* fix[dynamic-scripts-injection]: unregister content scripts before
registration ([hoxyq](https://github.com/hoxyq) in
[#26765](https://github.com/facebook/react/pull/26765))
2023-05-04 18:22:47 +01:00
Ruslan Lesiutin 377c5175f7 DevTools: fix backend activation (#26779)
## Summary
We have a case:
1. Open components tab
2. Close Chrome / Firefox devtools window completely
3. Reopen browser devtools panel
4. Open components tab

Currently, in version 4.27.6, we cannot load the components tree.

This PR contains two changes:
- non-functional refactoring in
`react-devtools-shared/src/devtools/store.js`: removed some redundant
type castings.
- fixed backend manager logic (introduced in
https://github.com/facebook/react/pull/26615) to activate already
registered backends. Looks like frontend of devtools also depends on
`renderer-attached` event, without it component tree won't load.

## How did you test this change?
This fixes the case mentioned prior. Currently in 4.27.6 version it is
not working, we need to refresh the page to make it work.

I've tested this in several environments: chrome, firefox, standalone
with RN application.
2023-05-04 17:34:57 +01:00
Sebastian Markbåge aef7ce5547 [Flight] Progressively Enhanced Server Actions (#26774)
This automatically exposes `$$FORM_ACTIONS` on Server References coming
from Flight. So that when they're used in a form action, we can encode
the ID for the server reference as a hidden field or as part of the name
of a button.

If the Server Action is a bound function it can have complex data
associated with it. In this case this additional data is encoded as
additional form fields.

To process a POST on the server there's now a `decodeAction` helper that
can take one of these progressive posts from FormData and give you a
function that is prebound with the correct closure and FormData so that
you can just invoke it.

I updated the fixture which now has a "Server State" that gets
automatically refreshed. This also lets us visualize form fields.
There's no "Action State" here for showing error messages that are not
thrown, that's still up to user space.
2023-05-03 18:36:57 -04:00
Sebastian Markbåge c10010a6a0 [Fizz] Gracefully handle suspending in DOM configs (#26768)
E.g. if we suspend (throw a promise) in pushStartInstance today we might
have already pushed some chunks (or even child segments potentially). We
should revert back to where we were.

This doesn't usually happen because when we suspend in a component it
doesn't write anything itself, it'll always defer to som host instance
to do the writing.

There was a todo about this already but I'm not 100% sure it's always
safe when suspending. It should be safe when suspending just regularly
because it's just a noop. We might not even want "throwing a promise" in
this mechanism to be supported longer term but for now that's how a
suspend in internals.
2023-05-03 18:13:47 -04:00
Andrew Gadzik 2c1117a8d0 Reuse request so that a ReabableStream body does not become disturbed (#26771) 2023-05-03 15:06:10 -04:00
Sebastian Markbåge fa7a447b9c [Fizz] Check for nullish values on ReactCustomFormAction (#26770)
Usually we don't have to do this since we only set these in the loop but
the ReactCustomFormAction props are optional so they might be undefined.

Also moved it to a general type since it's a semi-public API.
2023-05-03 14:35:26 -04:00
Andrew Clark b7972822b5 useOptimisticState -> useOptimistic (#26772)
Drop the "state". Just "useOptimistic". It's cleaner.

This is still an experimental API. May not be the final name.
2023-05-03 14:26:00 -04:00
Ruslan Lesiutin 8a25302c66 fix[dynamic-scripts-injection]: unregister content scripts before registration (#26765)
## Summary
Fixes #26756.

DevTools is failing to inject `__REACT_DEVTOOLS_GLOBAL_HOOK__` hook in
incognito mode. This is not happening straight-forward, but if extension
is toggled on and off, the next time I try to open it I am receiving an
error that content script was already registered.

<img width="676" alt="Screenshot 2023-05-02 at 14 36 53"
src="https://user-images.githubusercontent.com/28902667/235877692-51c5d284-79d9-4b00-b62e-d25d5bb5e056.png">

- Unregistering content scripts before attempting to register them
again. We need to inject `__REACT_DEVTOOLS_GLOBAL_HOOK__` on each page,
so this should be expected behaviour.
- Fixed error logging
 
## How did you test this change?
Local build of extension for Chrome, trying the same steps, which
resulted in an error.
No regression in performance, tested on react.dev, still the same.
2023-05-03 17:27:39 +01:00
Sebastian Markbåge 559e83aebb [Fizz] Allow an action provide a custom set of props to use for progressive enhancement (#26749)
Stacked on top of #26735.

This allows a framework to add a `$$FORM_ACTION` property to a function.
This lets the framework return a set of props to use in place of the
function but only during SSR. Effectively, this lets you implement
progressive enhancement of form actions using some other way instead of
relying on the replay feature.

This will be used by RSC on Server References automatically by
convention in a follow up, but this mechanism can also be used by other
frameworks/libraries.
2023-05-01 16:01:14 -04:00
Sebastian Markbåge 67f4fb0213 Allow forms to skip hydration of hidden inputs (#26735)
This allows us to emit extra ephemeral data that will only be used on
server rendered forms.

First I refactored the shouldSkip functions to now just do that work
inside the canHydrate methods. This makes the Config bindings a little
less surface area but it also helps us optimize a bit since we now can
look at the code together and find shared paths.

canHydrate returns the instance if it matches, that used to just be
there to refine the type but it can also be used to just return a
different instance later that we find. If we don't find one, we'll bail
out and error regardless so no need to skip past anything.
2023-05-01 15:35:57 -04:00
Josh Story 8ea96ef84d [Fizz] Encode external fizz runtime into chunks eagerly (#26752)
in https://github.com/facebook/react/pull/26738 we added nonce to the
ResponseState. Initially it was used in a variety of places but the
version that got merged only included it with the external fizz runtime.
This PR updates the config for the external fizz runtime so that the
nonce is encoded into the script chunks at request creation time.

The rationale is that for live-requests, streaming is more likely than
not so doing the encoding work at the start is better than during flush.
For cases such as SSG where the runtime is not required the extra
encoding is tolerable (not a live request). Bots are an interesting case
because if you want fastest TTFB you will end up requiring the runtime
but if you are withholding until the stream is done you have already
sacrificed fastest TTFB and the marginal slowdown of the extraneous
encoding is hopefully neglibible

I'm writing this so later if we learn that this tradeoff isn't worth it
we at least understand why I made the change in the first place.
2023-05-01 10:50:36 -07:00
Andrew Clark 491aec5d61 Implement experimental_useOptimisticState (#26740)
This adds an experimental hook tentatively called useOptimisticState.
(The actual name needs some bikeshedding.)

The headline feature is that you can use it to implement optimistic
updates. If you set some optimistic state during a transition/action,
the state will be automatically reverted once the transition completes.

Another feature is that the optimistic updates will be continually
rebased on top of the latest state.

It's easiest to explain with examples; we'll publish documentation as
the API gets closer to stabilizing. See tests for now.

Technically the use cases for this hook are broader than just optimistic
updates; you could use it implement any sort of "pending" state, such as
the ones exposed by useTransition and useFormStatus. But we expect
people will most often reach for this hook to implement the optimistic
update pattern; simpler cases are covered by those other hooks.
2023-05-01 13:19:20 -04:00
Dan Ott 9545e4810c Add nonce support to bootstrap scripts and external runtime (#26738)
Adds support for nonce on `bootstrapScripts`, `bootstrapModules` and the external fizz runtime
2023-05-01 09:19:02 -07:00
Andrew Clark 86b0e91998 Gate DevTools test to fix CI (#26742)
This test started failing recently in older versions of React because
the Scheduler priority inside a microtask is Normal instead of
Immediate. This is expected because microtasks are not Scheduler tasks;
it's an implementation detail.

I gated the test to only run in v17 because it's a regression test for
legacy Suspense behavior, and the implementation details of the snapshot
changed in v18.

Test plan
---------

Using latest:

```
yarn test --build --project devtools --release-channel=experimental profilingcache
```

Using v17 (typically runs in a timed CI workflow):

```
/scripts/circleci/download_devtools_regression_build.js 17.0 --replaceBuild
yarn test --build --project devtools --release-channel=experimental --reactVersion 17.0 profilingcache
```
2023-04-29 11:14:16 -04:00
Josh Story b12bea62d9 Preinits should support a nonce option (#26744)
Currently there is no way to provide a nonce when using
`ReactDOM.preinit(..., { as: 'script' })`

This PR adds `nonce?: string` as an option

While implementing this PR I added a test to also show you can pass
`integrity`. This test isn't directly related to the nonce change.
2023-04-28 15:57:39 -07:00
Sebastian Silbermann efbd68511d Remove unused initialStatus parameter from useHostTransitionStatus (#26743) 2023-04-28 23:18:10 +02:00
Andrew Clark 18282f881d Fix: Update while suspended fails to interrupt (#26739)
This fixes a bug with `use` where if you update a component that's
currently suspended, React will sometimes mistake it for a render phase
update.

This happens because we don't reset `currentlyRenderingFiber` until the
suspended is unwound. And with `use`, that can happen asynchronously,
most commonly when the work loop is suspended during a transition.

The fix is to make sure `currentlyRenderingFiber` is only set when we're
in the middle of rendering, which used to be true until `use` was
introduced.

More specifically this means clearing `currentlyRenderingFiber` when
something throws and setting it again when we resume work.

In many cases, this bug will fail "gracefully" because the update is
still added to the queue; it's not dropped completely. It's also
somewhat rare because it has to be the exact same component that's
currently suspended. But it's still a bug. I wrote a regression test
that shows a sync update failing to interrupt a suspended component.
2023-04-28 15:35:14 -04:00
Andrew Clark 540bab085d Implement experimental_useFormStatus (#26722)
This hook reads the status of its ancestor form component, if it exists.

```js
const {pending, data, action, method} = useFormStatus();
```

It can be used to implement a loading indicator, for example. You can
think of it as a shortcut for implementing a loading state with the
useTransition hook.

For now, it's only available in the experimental channel. We'll share
docs once its closer to being stable. There are additional APIs that
will ship alongside it.

Internally it's implemented using startTransition + a context object.
That's a good way to think about its behavior, but the actual
implementation details may change in the future.

Because form elements cannot be nested, the implementation in the
reconciler does not bother to keep track of multiple nested "transition
providers". So although it's implemented using generic Fiber config
methods, it does currently make some assumptions based on React DOM's
requirements.
2023-04-26 18:19:58 -04:00
Andrew Clark 6eadbe0c4a Fix: Resolve entangled actions independently (#26726)
When there are multiple async actions at the same time, we entangle them
together because we can't be sure which action an update might be
associated with. (For this, we'd need AsyncContext.) However, if one of
the async actions fails with an error, it should only affect that
action, not all the other actions it may be entangled with.

Resolving each action independently also means they can have independent
pending state types, rather than being limited to an `isPending`
boolean. We'll use this to implement an upcoming form API.
2023-04-25 20:43:20 -04:00
Josh Story ec5e9c2a75 Fix double preload (#26729)
I found a couple scenarios where preloads were issued too aggressively

1. During SSR, if you render a new stylesheet after the preamble flushed
it will flush a preload even if the resource was already preloaded
2. During Client render, if you call `ReactDOM.preload()` it will only
check if a preload exists in the Document before inserting a new one. It
should check for an underlying resource such as a stylesheet link or
script if the preload is for a recognized asset type
2023-04-25 15:10:34 -07:00
lauren 25b99efe0c [DevTools] Add support for useMemoCache (#26696)
useMemoCache wasn't previously supported in the DevTools, so any attempt
to inspect a component using the hook would result in a
`dispatcher.useMemoCache is not a function (it is undefined)` error.
2023-04-25 09:19:25 -07:00
Andrew Clark ed545ae3d3 Turn off enableFormActions in Meta build (#26721)
This is enabled in the canary channels, but because it's relatively
untested, we'll disable it at Meta until they're ready to start trying
it out. It can change some behavior even if you don't intentionally
start using the API.

The reason it's not a dynamic flag is that it affects the external Fizz
runtime, which currently can't read flags at runtime.
2023-04-25 12:01:34 -04:00
Sebastian Markbåge bf449ee74e Replay Client Actions After Hydration (#26716)
We used to have Event Replaying for any kind of Discrete event where
we'd track any event after hydrateRoot and before the async code/data
has loaded in to hydrate the target. However, this didn't really work
out because code inside event handlers are expected to be able to
synchronously read the state of the world at the time they're invoked.
If we replay discrete events later, the mutable state around them like
selection or form state etc. may have changed.

This limitation doesn't apply to Client Actions:

- They're expected to be async functions that themselves work
asynchronously. They're conceptually also in the "navigation" events
that happen after the "submit" events so they're already not
synchronously even before the first `await`.
- They're expected to operate mostly on the FormData as input which we
can snapshot at the time of the event.

This PR adds a bit of inline script to the Fizz runtime (or external
runtime) to track any early submit events on the page - but only if the
action URL is our placeholder `javascript:` URL. We track a queue of
these on `document.$$reactFormReplay`. Then we replay them in order as
they get hydrated and we get a handle on the Client Action function.

I add the runtime to the `bootstrapScripts` phase in Fizz which is
really technically a little too late, because on a large page, it might
take a while to get to that script even if you have displayed the form.
However, that's also true for external runtime. So there's a very short
window we might miss an event but it's good enough and better than
risking blocking display on this script.

The main thing that makes the replaying difficult to reason about is
that we can have multiple instance of React using this same queue. This
would be very usual but you could have two different Reacts SSR:ing
different parts of the tree and using around the same version. We don't
have any coordinating ids for this. We could stash something on the form
perhaps but given our current structure it's more difficult to get to
the form instance in the commit phase and a naive solution wouldn't
preserve ordering between forms.

This solution isn't 100% guaranteed to preserve ordering between
different React instances neither but should be in order within one
instance which is the common case.

The hard part is that we don't know what instance something will belong
to until it hydrates. So to solve that I keep everything in the original
queue while we wait, so that ordering is preserved until we know which
instance it'll go into. I ended up doing a bunch of clever tricks to
make this work. These could use a lot more tests than I have right now.

Another thing that's tricky is that you can update the action before
it's replayed but we actually want to invoke the old action if that
happens. So we have to extract it even if we can't invoke it right now
just so we get the one that was there during hydration.
2023-04-25 10:22:20 -04:00
Sebastian Markbåge 64d6be7122 Use require() to implement script src in tests (#26717)
We currently use rollup to make an adhoc bundle from the file system
when we're testing an import of an external file.

This doesn't follow all the interception rules that we use in jest and
in our actual builds.

This switches to just using jest require() to load these. This means
that they effectively have to load into the global document so this only
works with global document tests which is all we have now anyway.
2023-04-25 09:12:16 -04:00
Andrew Clark 919620b293 Add stub for experimental_useFormStatus (#26719)
This wires up, but does not yet implement, an experimental hook called
useFormStatus. The hook is imported from React DOM, not React, because
it represents DOM-specific state — its return type includes FormData as
one of its fields. Other renderers that implement similar methods would
use their own renderer-specific types.

The API is prefixed and only available in the experimental channel.

It can only be used from client (browser, SSR) components, not Server
Components.
2023-04-24 20:18:34 -04:00
Sebastian Markbåge 9ece58ebaa Go through the toString path for booleanish strings and .name property (#26720)
This is consistent with what we used to do but not what we want to do.
2023-04-24 19:26:50 -04:00
Sebastian Markbåge 5e5342b100 Insert temporary input node to polyfill submitter argument in FormData (#26714)
Insert temporary input node to polyfill submitter argument in FormData.
This works for buttons too and fixes a bug where the type attribute
wasn't reset.

I also exclude the submitter if it's a function action. This ensures
that we don't include the generated "name" when the action is a server
action. Conceptually that name doesn't exist.
2023-04-24 14:18:09 -04:00
Sophie Alpert 9ee7964302 Fix escaping in ReactDOMInput code (#26630)
JSON.stringify isn't the right thing here. Luckily this doesn't look to have any security impact.
2023-04-24 10:33:11 -07:00
Sebastian Markbåge 2fa6323818 Restore server controlled form fields to whatever they should be (#26708)
Fizz can emit whatever it wants for the SSR version of these fields when
it's a function action so they might not align with what is in the
previous props. Therefore we need to force them to update if we're
updating to a non-function where they might be relevant again.
2023-04-23 17:44:28 -04:00
Andrew Clark 7ce765ec32 Clean up enableUseHook flag (#26707)
This has been statically enabled everywhere for months.
2023-04-23 14:50:17 -04:00
Sebastian Markbåge a21d1475ff [Flight] Fix File Upload in Node.js (#26700)
Use the Blob constructor + append with filename instead of File
constructor. Node.js doesn't expose a global File constructor but does
support it in this form.

Queue fields until we get the 'end' event from the previous file. We
rely on previous files being available by the time a field is resolved.
However, since the 'end' event in Readable is fired after two
micro-tasks, these are not resolved in order.

I use a queue of the fields while we're still waiting on files to
finish. This still doesn't resolve files and fields in order relative to
each other but that doesn't matter for our usage.
2023-04-22 01:04:24 -04:00
Josh Story 36e4cbe2e9 [Float][Flight] Flight support for Float (#26502)
Stacked on #26557 

Supporting Float methods such as ReactDOM.preload() are challenging for
flight because it does not have an easy means to convey direct
executions in other environments. Because the flight wire format is a
JSON-like serialization that is expected to be rendered it currently
only describes renderable elements. We need a way to convey a function
invocation that gets run in the context of the client environment
whether that is Fizz or Fiber.

Fiber is somewhat straightforward because the HostDispatcher is always
active and we can just have the FlightClient dispatch the serialized
directive.

Fizz is much more challenging becaue the dispatcher is always scoped but
the specific request the dispatch belongs to is not readily available.
Environments that support AsyncLocalStorage (or in the future
AsyncContext) we will use this to be able to resolve directives in Fizz
to the appropriate Request. For other environments directives will be
elided. Right now this is pragmatic and non-breaking because all
directives are opportunistic and non-critical. If this changes in the
future we will need to reconsider how widespread support for async
context tracking is.

For Flight, if AsyncLocalStorage is available Float methods can be
called before and after await points and be expected to work. If
AsyncLocalStorage is not available float methods called in the sync
phase of a component render will be captured but anything after an await
point will be a noop. If a float call is dropped in this manner a DEV
warning should help you realize your code may need to be modified.

This PR also introduces a way for resources (Fizz) and hints (Flight) to
flush even if there is not active task being worked on. This will help
when Float methods are called in between async points within a function
execution but the task is blocked on the entire function finishing.

This PR also introduces deduping of Hints in Flight using the same
resource keys used in Fizz. This will help shrink payload sizes when the
same hint is attempted to emit over and over again
2023-04-21 20:45:51 -07:00
Andrew Clark 8f42196892 Change DOM HostContext to number instead of string (#26698)
In React DOM, we use HostContext to represent the namespace of whatever
is currently rendering — SVG, Math, or HTML. Because there is a fixed
set of possible values, we can switch this to be a number instead. My
motivation is that I want to start tracking additional information in
this type, and I want to pack all of it into a single number instead of
turning it into an object. For better performance.

(In dev, the host context type is already an object that includes
additional information, but that's dev so who cares.)

Technically, before this change, the host context could be any namespace
URI string, but any value other than SVG or Math was treated the same
way. Only SVG and Math have special behavior. So in the new structure,
there are three enum values: SVG, Math, or None, which represents the
HTML namespace as well as all other possible namespaces.
2023-04-21 21:44:43 -04:00
Andrew Clark fd3fb8e3c5 Rethrow errors from form actions (#26689)
This is the next step toward full support for async form actions.

Errors thrown inside form actions should cause the form to re-render and
throw the error so it can be captured by an error boundary. The behavior
is the same if the `<form />` had an internal useTransition hook, which
is pretty much exactly how we implement it, too.

The first time an action is called, the form's HostComponent is
"upgraded" to become stateful, by lazily mounting a list of hooks. The
rest of the implementation for function components can be shared.

Because the error handling behavior added in this commit is just using
useTransition under-the-hood, it also handles pending states, too.
However, this pending state can't be observed until we add a new hook
for that purpose. I'll add this next.
2023-04-21 13:29:46 -04:00