When scheduling the initial root and when using
`unstable_scheduleHydration` we should use the Hydration Lanes rather
than the raw update lane. This ensures that we're always hydrating using
a Hydration Lane or the Offscreen Lane rather than other lanes getting
some random hydration in it.
This fixes an issue where updating a root while it is still hydrating
causes it to trigger client rendering when it could just hydrate and
then apply the update on top of that.
It also fixes a potential performance issue where
`unstable_scheduleHydration` gets batched with an update that then ends
up forcing an update of a boundary that requires it to rewind to do the
hydration lane anyway. Might as well just start with the hydration
without the update applied first.
I added a kill switch (`enableHydrationLaneScheduling`) just in case but
seems very safe given that using `unstable_scheduleHydration` at all is
very rare and updating the root before the shell hydrates is extremely
rare (and used to trigger a recoverable error).
DiffTrain build for [d5e8f79cf4](https://github.com/facebook/react/commit/d5e8f79cf4d11fa7eee263b3f937deecbe65ffd7)
The need for this was removed in
https://github.com/facebook/react/pull/30831
Since the new DevTools version has been released for a while and we
expect people to more or less auto-update. Future versions of React
don't need this.
Once we remove the remaining uses of `getInstanceFromNode` e.g. in the
deprecated internal `findDOMNode`/`findNodeHandle` and the event system,
we can completely remove the tagging of DOM nodes.
DiffTrain build for [3b597c0576](https://github.com/facebook/react/commit/3b597c0576977773910c77e075cc6d6308decb04)
To avoid GC pressure and accidentally hanging onto old trees Suspense
boundary retries are now implemented in the commit phase. I used the
Callback flag which was previously only used to schedule callbacks for
Class components. This isn't quite semantically equivalent but it's
unused and seemingly compatible.
DiffTrain build for [de68d2f4a2](https://github.com/facebook/react/commit/de68d2f4a2403ad1ef46a3036ddc1f9080640588)
When streaming SSR while hydrating React will wait for Suspense
boundaries to be revealed by the SSR stream before attempting to hydrate
them. The rationale here is that the Server render is likely further
ahead of whatever the client would produce so waiting to let the server
stream in the UI is preferable to retrying on the client and possibly
delaying how quickly the primary content becomes available. However If
the connection closes early (user hits stop for instance) or there is a
server error which prevents additional HTML from being delivered to the
client this can put React into a broken state where the boundary never
resolves nor errors and the hydration never retries that boundary
freezing it in it's fallback state.
Once the document has fully loaded we know there is not way any
additional Suspense boundaries can arrive. This update changes react-dom
on the client to schedule client renders for any unfinished Suspense
boundaries upon document loading.
The technique for client rendering a fallback is pretty straight
forward. When hydrating a Suspense boundary if the Document is in
'complete' readyState we interpret pending boundaries as fallback
boundaries. If the readyState is not 'complete' we register an event to
retry the boundary when the DOMContentLoaded event fires.
To test this I needed JSDOM to model readyState. We previously had a
temporary implementation of readyState for SSR streaming but I ended up
implementing this as a mock of JSDOM that implements a fake readyState
that is mutable. It starts off in 'loading' readyState and you can
advance it by mutating document.readyState. You can also reset it to
'loading'. It fires events when changing states.
This seems like the least invasive way to get closer-to-real-browser
behavior in a way that won't require remembering this subtle detail
every time you create a test that asserts Suspense resolution order.
DiffTrain build for [16d2bbbd1f](https://github.com/facebook/react/commit/16d2bbbd1f1617d636ea0fd271b902a12a763c27)
Fixes a bug with the experimental `useResourceEffect` hook where we
would compare the wrong deps when there happened to be another kind of
effect preceding the ResourceEffect. To do this correctly we need to add
a pointer to the ResourceEffect's identity on the update.
I also unified the previously separate push effect impls for resource
effects since they are always pushed together as a unit.
DiffTrain build for [c11c9510fa](https://github.com/facebook/react/commit/c11c9510fa14bbd87053685c19bfdfec2f427f49)
This lets us track separately if something was suspended on an Action
using useActionState rather than suspended on Data.
This approach feels quite bloated and it seems like we'd eventually
might want to read more information about the Promise that suspended and
the context it suspended in. As a more general reason for suspending.
The way useActionState works in combination with the prewarming is quite
unfortunate because 1) it renders blocking to update the isPending flag
whether you use it or not 2) it prewarms and suspends the useActionState
3) then it does another third render to get back into the useActionState
position again.
DiffTrain build for [92c0f5f85f](https://github.com/facebook/react/commit/92c0f5f85fed42024b17bf6595291f9f5d6e8734)
## Summary
This fixes a typo in the error that gets reported when Float errors
while hoisting a style tag that does not contain both `precedence` and
`href`. There was a typo in _conflict_ and the last part of the sentence
doesn't make sense. I assume it wasn't needed since the message already
suggests moving the style tag to the head manually.
DiffTrain build for [63cde684f5](https://github.com/facebook/react/commit/63cde684f5340b1ca73f6244501aac1c3d2c92a8)
When you schedule a microtask from render or effect and then call
setState (or ping) from there, the "event" is the event that React
scheduled (which will be a postMessage). The event time of this new
render will be before the last render finished.
We usually clamp these but in this scenario the update doesn't happen
while a render is happening. Causing overlapping events.
Before:
<img width="1229" alt="Screenshot 2024-11-12 at 11 01 30 PM"
src="https://github.com/user-attachments/assets/9652cf3b-b358-453c-b295-1239cbb15952">
Therefore when we finalize a render we need to store the end of the last
render so when we a new update comes in later with an event time earlier
than that, we know to clamp it.
There's also a special case here where when we enter the
`RootDidNotComplete` or `RootSuspendedWithDelay` case we neither leave
the root as in progress nor commit it. Those needs to finalize too.
Really this should be modeled as a suspended track that we haven't added
yet. That's the gap between "Blocked" and "message" below.
After:
<img width="1471" alt="Screenshot 2024-11-13 at 12 31 34 AM"
src="https://github.com/user-attachments/assets/b24f994e-9055-4b10-ad29-ad9b36302ffc">
I also fixed an issue where we may log the same event name multiple
times if we're rendering more than once in the same event. In this case
I just leave a blank trace between the last commit and the next update.
I also adding ignoring of the "message" event at all in these cases when
the event is from React's scheduling itself.
DiffTrain build for [c13986da78](https://github.com/facebook/react/commit/c13986da7866a1a70a73b7ee05c87a9618ce6d03)
In preparation for the next RC, I set this feature flag to true
everywhere. I did not delete the feature flag yet, in case there are yet
more bugs to be discovered.
I also didn't remove the dynamic feature flag from the Meta builds; I'll
let the Meta folks handle that.
DiffTrain build for [988e217670](https://github.com/facebook/react/commit/988e2176702fca9b25113d9a8a3e7e3f484e16f2)
We've previously failed to land this change due to some internal apps
seeing infinite render loops due to external store state updates during
render. It turns out that since the `renderWasConcurrent` var was moved
into the do block, the sync render triggered from the external store
check was stuck with a `RootSuspended` `exitStatus`. So this is not
unique to sibling prerendering but more generally related to how we
handle update to a sync external store during render.
We've tested this build against local repros which now render without
crashes. We will try to add a unit test to cover the scenario as well.
---------
Co-authored-by: Andrew Clark <git@andrewclark.io>
Co-authored-by: Rick Hanlon <rickhanlonii@fb.com>
DiffTrain build for [989af12f72](https://github.com/facebook/react/commit/989af12f72080c17db03ead91d99b6394a215564)
## Summary
We're seeing certain situations in React Native development where ref
callbacks in `<Activity mode="hidden">` are sometimes invoked exactly
once with `null` without ever being called with a "current" value.
This violates the contract for refs because refs are expected to always
attach before detach (and to always eventually detach after attach).
This is *particularly* bad for refs that return cleanup functions,
because refs that return cleanup functions expect to never be invoked
with `null`. This bug causes such refs to be invoked with `null`
(because since `safelyAttachRef` was never called, `safelyDetachRef`
thinks the ref does not return a cleanup function and invokes it with
`null`).
This fix makes use of `offscreenSubtreeWasHidden` in
`commitDeletionEffectsOnFiber`, similar to how
https://github.com/facebook/react/commit/ec52a5698e2dfea7050a0b015f0b79abfb2d81b7
did this for `commitDeletionEffectsOnFiber`.
## How did you test this change?
We were able to isolate the repro steps to isolate the React Native
experimental changes. However, the repro steps depend on Fast Refresh.
```
function callbackRef(current) {
// Called once with `current` as null, upon triggering Fast Refresh.
}
<Activity mode="hidden">
<View ref={callbackRef} />;
</Activity>
```
Ideally, we would have a unit test that verifies this behavior without
Fast Refresh. (We have evidence that this bug occurs without Fast
Refresh in real product implementations. However, we have not
successfully deduced the root cause, yet.)
This PR currently includes a unit test that reproduces the Fast Refresh
scenario, which is also demonstrated in this CodeSandbox:
https://codesandbox.io/p/sandbox/hungry-darkness-33wxy7
Verified unit tests pass:
```
$ yarn
$ yarn test
# Run with `-r=www-classic` for `enableScopeAPI` tests.
$ yarn test -r=www-classic
```
Verified on the internal React Native development branch that the bug no
longer repros.
---------
Co-authored-by: Rick Hanlon <rickhanlonii@fb.com>
DiffTrain build for [ea3ac58669](https://github.com/facebook/react/commit/ea3ac586693014e882655728fc8396ecb1d6cf6e)
This reverts commit 6c4bbc7832.
It looked like the bug we found on the original land was related to
broken product code. But through landing #31268 we found additional bugs
internally. Since disabling the feature flag does not fix the bugs, we
have to revert again to unblock the sync. We can continue to debug with
our internal build.
DiffTrain build for [cae764ce81](https://github.com/facebook/react/commit/cae764ce81b1bd6c418e9e23651794b6b09208e8)
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
Currently, `react-hooks/rules-of-hooks` does not support `do/while`
loops - I've also reported this in
https://github.com/facebook/react/issues/28713.
This PR takes a stab at adding support for `do/while` by following the
same logic we already have for detecting `while` loops.
After this PR, any hooks called inside a `do/while` loop will be
considered invalid.
We're also adding some unit tests to confirm that the behavior is
working as expected.
Fixes#28713.
## How did you test this change?
<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
If you leave this empty, your PR will very likely be closed.
-->
I've added unit tests that cover the case and verified that they pass by
running:
```
yarn test packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js --watch
```
I've also verified that the rest of the tests continue to pass by
running:
```
yarn test
```
and
```
yarn test --prod
```
DiffTrain build for [9daabc0bf9](https://github.com/facebook/react/commit/9daabc0bf97805be23f6131be4d84d063a3ff446)
In order to support using the compiler on versions of React prior to 19,
we need the ability to statically import `c` (aka useMemoCache) or
fallback to a polyfill supplied by `react-compiler-runtime` (note: this
is a separate npm package, not to be confused with
`react/compiler-runtime`, which is currently a part of react).
To do this we first need to re-export `useMemoCache` under the top level
React namespace again, which is additive and thus non-breaking. Doing so
allows `react-compiler-runtime` to statically either re-export
`React.__COMPILER_RUNTIME.c` or supply a polyfill, without the need for
a dynamic import which is finicky to support due to returning a promise.
In later PRs I will remove `react/compiler-runtime` and update the
compiler to emit imports to `react-compiler-runtime` instead.
DiffTrain build for [b78a7f2f35](https://github.com/facebook/react/commit/b78a7f2f35e554a8647c3262d7f392e68d06febc)
We're seeing issues with this feature internally including bugs with
sibling prerendering and errors that are difficult for developers to
action on. We'll turn off the feature for the time being until we can
improve the stability and ergonomics.
This PR does two things:
- Turn off `enableInfiniteLoopDetection` everywhere while leaving it as
a variant on www so we can do further experimentation.
- Revert https://github.com/facebook/react/pull/31061 which was a
temporary change for debugging. This brings the feature back to
baseline.
DiffTrain build for [d8c90fa48d](https://github.com/facebook/react/commit/d8c90fa48d3addefe4b805ec56a3c65e4ee39127)
When a synchronous update suspends, and we prerender the siblings, the
prerendering should be non-blocking so that we can immediately restart
once the data arrives.
This happens automatically when there's a Suspense boundary, because we
immediately commit the boundary and then proceed to a Retry render,
which are always concurrent. When there's not a Suspense boundary, there
is no Retry, so we need to take care to switch from the synchronous work
loop to the concurrent one, to enable time slicing.
DiffTrain build for [0f1856c49f](https://github.com/facebook/react/commit/0f1856c49febe96923e469f98c0b123130ea015c)
Over time the behavior of these two paths has converged to be
essentially the same. So this merges them back into one function. This
should save some code size and also make it harder for the behavior to
accidentally diverge. (For the same reason, rolling out this change
might expose some areas where we had already accidentally diverged.)
DiffTrain build for [3c7667a694](https://github.com/facebook/react/commit/3c7667a694face1827356a7c90ee6f86a9c0baa0)
We're seeing the limit hit in some tests after enabling sibling
prerendering. Let's bump the limit so we can run more tests and gather
more signal on the changes. When we understand the scope of the problem
we can determine whether we need to change how the updates are counted
in prerenders and/or fix specific areas of product code.
DiffTrain build for [f9ebd85a19](https://github.com/facebook/react/commit/f9ebd85a196948be17efdd6774b4d0464b3b1f53)
A slight behavior change here too is that I now mark the start of the
commit phase before the BeforeMutationEffect phase. This affects
`<Profiler>` too.
The named sequences are as follows:
Render -> Suspended or Throttled -> Commit -> Waiting for Paint ->
Remaining Effects
The Suspended phase is only logged if we delay the Commit due to CSS /
images.
The Throttled phase is only logged if we delay the commit due to the
Suspense throttling timer.
<img width="1246" alt="Screenshot 2024-09-20 at 9 14 23 PM"
src="https://github.com/user-attachments/assets/8d01f444-bb85-472b-9b42-6157d92c81b4">
I don't yet log render phases that don't complete. I think I also need
to special case renders that or don't commit after being suspended.
DiffTrain build for [4e9540e3c2](https://github.com/facebook/react/commit/4e9540e3c2a8f9ae56318b967939c99b3a815190)