* Replace flushDiscreteUpdates with flushSync
flushDiscreteUpdates is almost the same as flushSync. It forces passive
effects to fire, because of an outdated heuristic, which isn't ideal but
not that important.
Besides that, the only remaining difference between flushDiscreteUpdates
and flushSync is that flushDiscreteUpdates does not warn if you call it
from inside an effect/lifecycle. This is because it might get triggered
by a nested event dispatch, like `el.focus()`.
So I added a new method, flushSyncWithWarningIfAlreadyRendering, which
is used for the public flushSync API. It includes the warning. And I
removed the warning from flushSync, so the event system can call that
one. In production, flushSyncWithWarningIfAlreadyRendering gets inlined
to flushSync, so the behavior is identical.
Another way of thinking about this PR is that I renamed flushSync to
flushSyncWithWarningIfAlreadyRendering and flushDiscreteUpdates to
flushSync (and fixed the passive effects thing). The point is to prevent
these from subtly diverging in the future.
* Invert so the one with the warning is the default one
To make Seb happy
Now that discrete updates are flushed synchronously in a microtask,
the `discreteUpdates` method used by our event system is only a
optimization to save us from having to check `window.event.type` on
every update. So we should be able to remove the extra logic.
Assuming this lands successfully, we can remove `batchedEventUpdates`
and probably inline `discreteUpdates` into the renderer, like we do
for continuous updates.
When migrating some internal tests I found it annoying that I couldn't
return anything from the `act` scope. You would have to declare the
variable on the outside then assign to it. But this doesn't play well
with type systems — when you use the variable, you have to check
the type.
Before:
```js
let renderer;
act(() => {
renderer = ReactTestRenderer.create(<App />);
})
// Type system can't tell that renderer is never undefined
renderer?.root.findByType(Component);
```
After:
```js
const renderer = await act(() => {
return ReactTestRenderer.create(<App />);
})
renderer.root.findByType(Component);
```
* Move error logging to update callback
This prevents double logging for gDSFE boundaries with createRoot.
* Add an explanation for the rest of duplicates
* Enable skipped tests from #21723
* Report uncaught errors in DEV
* Clear caught error
This is not necessary (as proven by tests) because next invokeGuardedCallback clears it anyway. But I'll keep it for consistency with other calls.
When wrapping an update in act, instead of scheduling a microtask,
we can add the task to our internal queue.
The benefit is that the user doesn't have to await the act call. We can
flush the work synchronously. This doesn't account for microtasks that
are scheduled in userspace, of course, but it at least covers
React's usage.
Change format of @next and @experimental release versions from <number>-<sha> to <number>-<sha>-<date> to make them more human readable. This format still preserves the ability for us to easily map a version number to the changes it contains, while also being able to more easily know at a glance how recent a release is.
* Move internal version of act to shared module
No reason to have three different copies of this anymore.
I've left the the renderer-specific `act` entry points because legacy
mode tests need to also be wrapped in `batchedUpdates`. Next, I'll update
the tests to use `batchedUpdates` manually when needed.
* Migrates tests to use internal module directly
Instead of the `unstable_concurrentAct` exports. Now we can drop those
from the public builds.
I put it in the jest-react package since that's where we put our other
testing utilities (like `toFlushAndYield`). Not so much so it can be
consumed publicly (nobody uses that package except us), but so it works
with our build tests.
* Remove unused internal fields
These were used by the old act implementation. No longer needed.
Currently, in a React 18 root, `act` only works if you mock the
Scheduler package. This was because we didn't want to add additional
checks at runtime.
But now that the `act` testing API is dev-only, we can simplify its
implementation.
Now when an update is wrapped with `act`, React will bypass Scheduler
entirely and push its tasks onto a special internal queue. Then, when
the outermost `act` scope exists, we'll flush that queue.
I also removed the "wrong act" warning, because the plan is to move
`act` to an isomorphic entry point, simlar to `startTransition`. That's
not directly related to this PR, but I didn't want to bother
re-implementing that warning only to immediately remove it.
I'll add the isomorphic API in a follow up.
Note that the internal version of `act` that we use in our own tests
still depends on mocking the Scheduler package, because it needs to work
in production. I'm planning to move that implementation to a shared
(internal) module, too.
* Delete test-utils implementation of `act`
Since it's dev-only now, we can use the one provided by the reconciler.
* Move act related stuff out of EventInternals
Upgrades the deprecation warning to a runtime error.
I did it this way instead of removing the export so the type is the same
in both builds. It will get dead code eliminated regardless.
This adds a new top level API for hydrating a root. It takes the initial
children as part of its constructor. These are unlike other render calls
in that they have to represent what the server sent and they can't be
batched with other updates.
I also changed the options to move the hydrationOptions to the top level
since now these options are all hydration options.
I kept the createRoot one just temporarily to make it easier to codemod
internally but I'm doing a follow up to delete.
As part of this I un-dried a couple of paths. ReactDOMLegacy was intended
to be built on top of the new API but it didn't actually use those root
APIs because there are special paths. It also doesn't actually use most of
the commmon paths since all the options are ignored. It also made it hard
to add only warnings for legacy only or new only code paths.
I also forked the create/hydrate paths because they're subtly different
since now the options are different. The containers are also different
because I now error for comment nodes during hydration which just doesn't
work at all but eventually we'll error for all createRoot calls.
After some iteration it might make sense to break out some common paths but
for now it's easier to iterate on the duplicates.
* Use the server src files as entry points for the builds/tests
We need one top level entry point to target two builds so we can't have
the top level one be the entry point for the builds.
* Same thing but with the modern entry point
* Clean up partial renderer entry points
I made a mistake by leaving server.browser.stable in which is the partial
renderer for the browser build of stable. That should use the legacy fizz
one.
Since the only usage of the partial renderer now is at FB and we don't use
it with Node, I removed the Node build of partial renderer too.
* Remove GC test
No code is running this path anymore. Ideally this should be ported to
a Fizz form.
This makes it a lot easier to render the whole document using React without
needing to patch into the stream.
We expect that currently people will still have to patch into the stream
to do advanced things but eventually the goal is that you shouldn't
need to.
* Wire up DOM legacy build
* Hack to filter extra comments for testing purposes
* Use string concat in renderToString
I think this might be faster. We could probably use a combination of this
technique in the stream too to lower the overhead.
* Error if we can't complete the root synchronously
Maybe this should always error but in the async forms we can just delay
the stream until it resolves so it does have some useful semantics.
In the synchronous form it's never useful though. I'm mostly adding the
error because we're testing this behavior for renderToString specifically.
* Gate memory leak tests of internals
These tests don't translate as is to the new implementation and have been
ported to the Fizz tests separately.
* Enable Fizz legacy mode in stable
* Add wrapper around the ServerFormatConfig for legacy mode
This ensures that we can inject custom overrides without negatively
affecting the new implementation.
This adds another field for static mark up for example.
* Wrap pushTextInstance to avoid emitting comments for text in static markup
* Don't emit static mark up for completed suspense boundaries
Completed and client rendered boundaries are only marked for the client
to take over.
Pending boundaries are still supported in case you stream non-hydratable
mark up.
* Wire up generateStaticMarkup to static API entry points
* Mark as renderer for stable
This shouldn't affect the FB one ideally but it's done with the same build
so let's hope this works.