In InferTypes when we infer types for properties during destructuring, we were breaking out of the loop when we encounter a hole in the array. Instead we should just skip that element and continue inferring later properties.
Closes#34748
Treat fake eval anonymous stacks as built-in. Hide built-in stack frames
unless they're used to call into a non-ignored stack frame.
The two main things to fix here is that 1) we're showing a linkified
stack for fake anonymous and 2) we're showing only built-ins when the
stack is completely internal. Meaning framework code is all noise.
Fixes https://github.com/facebook/react/issues/34770.
We need to clear measures at some point, otherwise all these copies of
props that we end up recording will allocate too much memory in
Chromium. This adds `performance.clearMeasures(...)` calls to such cases
in DEV.
Validated that entries are still shown on Performance panel timeline.
Stacked on #34829.
This lets you get an overview more easily when there's lots of things
like scripts downloading. Pluralized the name. E.g. `script` ->
`scripts` or `fetch` -> `fetches`.
This only groups them consecutively when they'd have the same place in
the list anyway because otherwise it might cover up some kind of
waterfall effects.
<img width="404" height="225" alt="Screenshot 2025-10-13 at 12 06 51 AM"
src="https://github.com/user-attachments/assets/da204a8e-d5f7-4eb0-8c51-4cc5bfd184c4"
/>
Expanded:
<img width="407" height="360" alt="Screenshot 2025-10-13 at 12 07 00 AM"
src="https://github.com/user-attachments/assets/de3c3de9-f314-4c87-b606-31bc49eb4aba"
/>
This lets you assign a name to a Promise that's passed into first party
code from third party since it otherwise would have no other stack frame
to indicate its name since the whole creation stack would be in third
party.
We already respect the `displayName` on the client but it's more
complicated on the server because we don't only consider the exact
instance passed to `use()` but the whole await sequence and we can pick
any Promise along the way for consideration. Therefore this also adds a
change where we pick the Promise node for consideration if it has a name
but no stack. Where we otherwise would've picked the I/O node.
Another thing that this PR does is treat anonymous stack frames (empty
url) as third party for purposes of heuristics like "hasUnfilteredFrame"
and the name assignment. This lets you include these in the actual
generated stacks (by overriding `filterStackFrame`) but we don't
actually want them to be considered first party code in the heuristics
since it ends up favoring those stacks and using internals like
`Function.all` in name assignment.
The index is both used as the key and for hydration purposes. Previously
we didn't preserve the index when sorting so the index didn't line up
which caused hydration to be the wrong slot when sorted.
`isStrictModeNonCompliant` on the root just means that it supports
strict mode. It's inherited by other nodes.
It's not possible to opt-in to strict mode on the root itself but rather
right below it. So we should not mark the root as being non-compliant.
This lets you select the root in the suspense tab and it shouldn't show
as red with a warning.
This ignore a Suspense boundary from the timeline when it has no visual
representation. No rect. In effect, this is not blocking the user
experience.
Technically it could be an effect that mounts which can have a
side-effect which is visible.
It could also be a meta-data tag like `<title>` which is visible. We
could hoistables a virtual representation by giving them a virtual rect.
E.g. at the top of the page. This could be added after the fact.
This ensures that we don't scroll on changes to the timeline such as
when loading a new page or while the timeline is still loading.
We only auto scroll to a boundary when we perform an explicit operation
from the user.
If an inner Offscreen commits an unhide, but an outer Offscreen is still
hidden but they're controlling the same DOM node then we shouldn't
unhide the DOM node yet.
This keeps track of whether we're directly inside a hidden offscreen. It
might be better to just do the tree search instead of keeping the stack
state since it's a rare case. Although this hide/unhide path does
trigger a lot of times even when there's no change.
This was technically a bug with Suspense too but it doesn't appear
because a suspended Suspense boundary never commits its partial state.
If it did, it would trigger this same path. But it can happen with an
outer Activity and inner Suspense.
When a debug channel is hooked up, and we're serializing debug models,
if the result is an already outlined reference, we can emit it directly,
without also outlining the reference. This would create an unnecessary
indirection.
Before:
```
:N1760023808330.2688
0:D"$2"
0:D"$3"
0:D"$4"
0:"hi"
1:{"name":"Component","key":null,"env":"Server","stack":[],"props":{}}
2:{"time":3.0989999999999327}
3:"$1"
4:{"time":3.261792000000014}
```
After:
```
:N1760023786873.8916
0:D"$2"
0:D"$1"
0:D"$3"
0:"hi"
1:{"name":"Component","key":null,"env":"Server","stack":[],"props":{}}
2:{"time":2.4145829999999933}
3:{"time":2.5488749999999527}
```
Notice how the second debug info chunk is now directly referencing chunk
`1` in the debug channel, without outlining and referencing `"$1"` as
its own debug chunk `3`.
This not only simplifies the RSC payload, and reduces overhead. But more
importantly it helps the client resolve cyclic references when a model
has debug info that has a reference back to the model. The client is
currently not able to resolve such a cycle when those chunk indirections
are involved. Ideally, it would also be able to resolve them regardless,
but that requires more work. In the meantime, this fixes an immediate
issue.
<!--
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?
-->
Fixes a syntax error causing the Compiler playground to crash. Resolves
https://github.com/facebook/react/issues/34622.
## 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.
-->
Tested locally and added a test.
<img width="1470" height="836" alt="Screenshot 2025-09-27 at 8 13 07 AM"
src="https://github.com/user-attachments/assets/29473682-94c3-49dc-9ee9-c2004062aaea"
/>
<!--
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
This pull request fixes a small UI issue in the React Developer Tools
settings panel.
The “Display density” field was appearing twice in the General tab.
Fix : https://github.com/facebook/react/issues/34791
Renames the `recommended` property on LintRule to `preset`, to allow
exporting rules for different presets. For now the `Recommended` and
`RecommendedLatest` presets are the same, but in the next PR I will
enable more rules for the latest preset.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34782).
* #34783
* __->__ #34782
For 7.0.0:
Slim down presets to just 2 configurations:
- `recommended`: legacy and flat config with all recommended rules, and
- `recommended-latest`: legacy and flat config with all recommended
rules plus new bleeding edge experimental compiler rules
Removed:
- `recommended-latest-legacy`
- `flat/recommended`
Please see the README for new install instructions.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34757).
* #34783
* #34782
* __->__ #34757
There's a couple of issues with serializing Buffer in the debug renders.
For one, the Node.js Buffer has a `toJSON` on it which turns the binary
data into a JSON array which is very inefficient to serialize compared
to the real buffer. For debug info we never really want to resolve these
and unlike the regular render we can't error. So this uses the trick
where we read the original value. It's still unfortunate that this
intermediate gets created at all but at least now we're not serializing
it.
Second, we have a limit on depth of objects but we didn't have a limit
on width like large arrays or typed arrays. This omits large arrays from
the payload when possible and make them deferred when there's a debug
channel.
## Overview
This PR adds the `ref` prop to `<Fragment>` in `react@canary`.
This means this API is ready for final feedback and prepared for a
semver stable release.
## What this means
Shipping Fragment refs to canary means they have gone through extensive
testing in production, we are confident in the stability of the APIs,
and we are preparing to release it in a future semver stable version.
Libraries and frameworks following the [Canary
Workflow](https://react.dev/blog/2023/05/03/react-canaries) should begin
implementing and testing these features.
## Why we follow the Canary Workflow
To prepare for semver stable, libraries should test canary features like
Fragment refs with `react@canary` to confirm compatibility and prepare
for the next semver release in a myriad of environments and
configurations used throughout the React ecosystem. This provides
libraries with ample time to catch any issues we missed before slamming
them with problems in the wider semver release.
Since these features have already gone through extensive production
testing, and we are confident they are stable, frameworks following the
[Canary Workflow](https://react.dev/blog/2023/05/03/react-canaries) can
also begin adopting canary features like Fragment refs.
This adoption is similar to how different Browsers implement new
proposed browser features before they are added to the standard. If a
frameworks adopts a canary feature, they are committing to stability for
their users by ensuring any API changes before a semver stable release
are opaque and non-breaking to their users.
Apps not using a framework are also free to adopt canary features like
Fragment refs as long as they follow the [Canary
Workflow](https://react.dev/blog/2023/05/03/react-canaries), but we
generally recommend waiting for a semver stable release unless you have
the capacity to commit to following along with the canary changes and
debugging library compatibility issues.
Waiting for semver stable means you're able to benefit from libraries
testing and confirming support, and use semver as signal for which
version of a library you can use with support of the feature.
## Docs
Check out the ["React Labs: View Transitions, Activity, and
more"](https://react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more#fragment-refs)
blog post, and [the new docs for Fragment
refs`](https://react.dev/reference/react/Fragment#fragmentinstance) for
more info.
## Overview
This PR ships the View Transition APIs to `react@canary`:
- [`<ViewTransition
/>`](https://react.dev/reference/react/ViewTransition)
-
[`addTransitionType`](https://react.dev/reference/react/addTransitionType)
This means these APIs are ready for final feedback and prepare for
semver stable release.
## What this means
Shipping `<ViewTransition />` and `addTransitionType` to canary means
they have gone through extensive testing in production, we are confident
in the stability of the APIs, and we are preparing to release it in a
future semver stable version.
Libraries and frameworks following the [Canary
Workflow](https://react.dev/blog/2023/05/03/react-canaries) should begin
implementing and testing these features.
## Why we follow the Canary Workflow
To prepare for semver stable, libraries should test canary features like
`<ViewTransition />` with `react@canary` to confirm compatibility and
prepare for the next semver release in a myriad of environments and
configurations used throughout the React ecosystem. This provides
libraries with ample time to catch any issues we missed before slamming
them with problems in the wider semver release.
Since these features have already gone through extensive production
testing, and we are confident they are stable, frameworks following the
[Canary Workflow](https://react.dev/blog/2023/05/03/react-canaries) can
also begin adopting canary features like `<ViewTransition />`.
This adoption is similar to how different Browsers implement new
proposed browser features before they are added to the standard. If a
frameworks adopts a canary feature, they are committing to stability for
their users by ensuring any API changes before a semver stable release
are opaque and non-breaking to their users.
Apps not using a framework are also free to adopt canary features like
`<ViewTransition>` as long as they follow the [Canary
Workflow](https://react.dev/blog/2023/05/03/react-canaries), but we
generally recommend waiting for a semver stable release unless you have
the capacity to commit to following along with the canary changes and
debugging library compatibility issues.
Waiting for semver stable means you're able to benefit from libraries
testing and confirming support, and use semver as signal for which
version of a library you can use with support of the feature.
## Docs
Check out the ["React Labs: View Transitions, Activity, and
more"](https://react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more#view-transitions)
blog post, and [the new docs for `<ViewTransition
/>`](https://react.dev/reference/react/ViewTransition) and
[`addTransitionType`](https://react.dev/reference/react/addTransitionType)
for more info.
Adds back HermesParser to eslint-plugin-react-hooks. There are still
[external users of
Flow](https://github.com/facebook/react/pull/34719#issuecomment-3368137743)
using the plugin, so we shouldn't break the plugin for them. However, we
still have the problem of double parsing: once from eslint (which we
discard) and then another via babel/hermes parser.
In the long run we should investigate a translation layer from estree to
babel (or alternatively, update the compiler to take estree as input).
But for now, I am reverting the PR.
This does mean that [Sandpack in
react.dev](11cb6b5915/src/components/MDX/Sandpack/runESLint.tsx (L31))
cannot update to the latest eprh as HermesParser does not appear to be
able to be run in a browser. I discovered this while trying to update
eprh on react.dev last week, but didn't investigate deeply. I'll need to
double check that again to find out more.
Another attempt to fix#34745. I updated our fixture for eslint-v9 to
include running tsc. I believe there were 2 issues:
1. `export * from './cjs/eslint-plugin-react-hooks'` in npm/index.d.ts
was no longer correct as we updated index.ts to export default instead
of named exports
2. After fixing ^ there was a typescript error which I fixed by making
some small tweaks
We override Cmd+F to jump to our search input instead of searching
through the HTML. This is ofc critical since our view virtualized.
However, Chrome DevTools installs its own listener on the document as
well (in the bubble phase) so if we prevent it at the document level
it's too late and it ends up stealing the focus instead. If we instead
listen at the documentElement it works as intended.
The workflow was correctly publishing the package(s) specified in
`only`, but due to incorrect logic it would also run the 'Publish all
packages' step.
Partial redo of #34710. The changes there tried to use `z.function(args,
return)` to be compatible across Zod v3 and v4, but Zod 4's function API
has completely changed. Instead, I've updated to just use `z.any()`
where we expect a function, and manually validate that it's a function
before we call the value. We already have validation of the return type
(also using Zod).
Co-authored-by: kolvian <eliot@pontarelli.com>
We will be focusing eslint-plugin-react-hooks as the primary OSS-only
package for our lint plugin. eslint-plugin-react-compiler will remain as
a Meta only package as some limitations of our internal infra require us
to use packages that aren't widely adopted by the rest of the industry.
This PR removes `hermes-parser`, which was meant to support parsing Flow
syntax.
Fixed two small issues with the config panel in the compiler playground:
1. Object descriptions were being confined in the config box and most of
it would not be visible upon hover
2. Changed it so that "Applied Configs" would only display a valid set
of configs, rather than switching between "Invalid Configs" and the set
of options. This would be less visually jarring for users as the Output
panel already displays errors. Additionally, if users want to see the
list of config options but have a currently broken config, they would
previously not know how to fix it.
Object hover before:
<img width="702" height="481" alt="Screenshot 2025-09-26 at 10 41 03 AM"
src="https://github.com/user-attachments/assets/b2ddec2f-16ba-41a1-be1f-96211f46764c"
/>
Hover after:
<img width="702" height="481" alt="Screenshot 2025-09-26 at 10 40 37 AM"
src="https://github.com/user-attachments/assets/dc713a22-4710-46a8-a5d7-485060cc9074"
/>
Applied Configs always displays the last valid set of configs:
https://github.com/user-attachments/assets/2fb9232f-7388-4488-9b7a-bb48bf09e4ca
Stacked on #34544
We only have getBoundingClientRect available from RN currently. This
should work as a substitute for this case because the equivalent of
multi-rect elements in RN is a nested Text component. We only include
the rects of top-level host components here so we can assume that
calling getBoundingClientRect on each child is the same result.
Tested in react-native with Fantom.
Stacked on #34533 for root fragment handling
This is the same approach as DOM, where we call getRootNode on the
parent.
Tests are in react-native using Fantom.
This rule was a leftover from a while ago and doesn't actually lint
anything useful. Specifically, you get a lint error if you try to opt
out a component that isn't already bailing out. If there's a bailout the
compiler already safely skips over it, so adding `'use no memo'` there
is unnecessary.
Fixes#31407
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34703).
* __->__ #34703
* #34700
Previously, the `recommended` config used the legacy ESLint format
(plugins as an array of strings). This causes errors when used with
ESLint v9's `defineConfig()` helper. This was following [eslint's own
docs](https://eslint.org/docs/latest/extend/plugins#backwards-compatibility-for-legacy-configs):
> With this approach, both configuration systems recognize
"recommended". The old config system uses the recommended key while the
current config system uses the flat/recommended key. The defineConfig()
helper first looks at the recommended key, and if that is not in the
correct format, it looks for the flat/recommended key. This allows you
an upgrade path if you’d later like to rename flat/recommended to
recommended when you no longer need to support the old config system.
However,
[`isLegacyConfig()`](https://github.com/eslint/rewrite/blob/main/packages/config-helpers/src/define-config.js#L73-L81)
(also see
[`eslintrcKeys`](https://github.com/eslint/rewrite/blob/main/packages/config-helpers/src/define-config.js#L24-L35))
function doesn't check for the `plugins` key, so our config was
incorrectly treated as flat config despite being in legacy format.
This PR fixes the issue, along with a few other fixes combined:
1. Convert `recommended` to flat config format
2. Separate basic rules (exhaustive-deps, rules-of-hooks) from compiler
rules
3. Add `recommended-latest-legacy` config for non-flat config users who
want all recommended rules (including compiler rules)
4. Adding more types for the exported config
Our shipped presets in 6.x.x will essentially be:
- `recommended-legacy`: legacy (non-flat), with basic rules only
- `recommended-latest-legacy`: legacy (non-flat), all rules (basic +
compiler)
- `flat/recommended`: flat, basic rules only (now the same as
recommended, but to avoid making a breaking change we'll just keep it
around in 6.x.x)
- `recommended-latest`: flat, all rules (basic + compiler)
- `recommended`: flat, basic rules only
In the next breaking release 7.x.x, we will collapse down the presets
into three:
- `recommended-legacy`: all recommended rules
- `recommended`: all recommended rules
- `recommended-experimental`: all recommended rules + new bleeding edge
experimental rules
Closes#34679
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34700).
* #34703
* __->__ #34700
This auto updates to select the last entry in the timeline until we make
the first selection. That way when new content loads in, we show the
last timeline of what is visible.
When we flush a Suspense boundary we might not flush the fallback
segment, it might only flush a placeholder instead. In this case the
segment can flush again but we do not want to flush the boundary itself
a second time. We now detach the boundary after flushing it.
better solution to: https://github.com/facebook/react/pull/34668
We're showing too much noise in the side-panel when selecting a Suspense
boundary. The interesting thing to see directly is the "Suspended by".
The "props" are mostly useless because the `"name"` prop is already in
the tree. I'm now also showing it in the title bar of the selected
element panel. The "children" and "fallback" props are just the thing
that you can see in the tree view anyway.
The "state" is this weird section with just one field in it, which we
already have duplicated in the top toolbar as well. We can just delete
this. I make sure to show the icon and a "suspended..." section while
the boundary is still loading but now yet resuspended by force
suspending.
While still loading:
<img width="600" height="193" alt="Screenshot 2025-09-27 at 11 54 37 PM"
src="https://github.com/user-attachments/assets/1c3f3a96-46e0-4b11-806f-032569c7d5b5"
/>
After loading:
<img width="602" height="266" alt="Screenshot 2025-09-27 at 11 54 53 PM"
src="https://github.com/user-attachments/assets/c43cc4cb-036f-4ced-9b0d-226c6320cd76"
/>
Resuspended after loading:
<img width="602" height="300" alt="Screenshot 2025-09-27 at 11 55 07 PM"
src="https://github.com/user-attachments/assets/0be01735-48a7-47dc-b5cf-e72ec71e0148"
/>
Rebased on #34454.
Always include the root in the timeline even if it has no unique
suspenders, since even if it won't suspend, we have to be able to see
that and step to one step before the next boundary to see the first
boundary that does suspend in its fallback state.
Also, if there's no current selection on initial mount, select the last
entry in the timeline. We usually do this with `selectedSuspenseID` but
that doesn't happen on initial load. So this does it on initial load if
nothing else is selected by then. That way when you reload you get the
initial root selected.
There's a problem here because we should really use one source of truth
and `selectedSuspenseID` doesn't really do anything now. Either it
should be its separate source of truth and you can't show components in
the side-panel or it should be derived from the other state.
If it's derived, once there's a selection, e.g. in the root, then even
if new timelines load it will never change but that's probably a good
thing.
This enables `@enablePreserveExistingMemoizationGuarantees` by default.
As of the previous PR (#34503), this mode now enables the following
behaviors:
- Treating variables referenced within a `useMemo()` or `useCallback()`
as "frozen" (immutable) as of the start of the call. Ie, the compiler
will assume that the values you reference are not mutated by the body of
the useMemo, not are they mutated later. Directly modifying them (eg
`var.property = true`) will be an error.
- Similarly, the results of the useMemo/useCallback are treated as
frozen (immutable) after the call.
These two rules match the behavior for other hooks: this means that
developers will see similar behavior to swapping out `useMemo()` for a
custom `useMyMemo()` wrapper/alias.
Additionally, as of #34503 the compiler uses information from the manual
dependencies to know which variables are non-nullable. Even if a useMemo
block conditionally accesses a nested property — `if (cond) { log(x.y.z)
}` — where the compiler would not usually know that `x` is non-nullable,
if the user specifies `x.y.z` as a manual dependency then the compiler
knows that `x` and `x.y` are non-nullable and can infer a more precise
dependency.
Finally, this mode also ensures that we always memoize function calls
that return primitives. See #34343 for more details.
For now, I've explicitly opted out of this feature in all test fixtures
where the behavior changed.
The `@enablePreserveExistingMemoizationGuarantees` mode can still fail
to preserve manual memoization due to mismtached dependencies.
Specifically, where the user's dependencies are more precise than the
compiler infers bc the compiler is being conservative about what might
be nullable. In this mode though we're intentionally using information
from the manual memoization and can also rely on the deps as a signal
for what's non-nullable.
The idea of the PR is that we treat manual memo deps just like other
inferred-as-non-nullable objects during PropagateScopeDeps. We're
careful to not treat the full path as non-nullable, only up to the last
property index. So `x.y.z` as a manual dep treats `x` and `x.y` as
non-nullable, allowing us to preserve a conditional dependency on
`x.y.z`.
Optionals within manual dependencies are a bit trickier and aren't
handled yet, but hopefully that's less common and something we can
improve in a follow-up. Not handling them just means that developers may
hit false positives on validating existing memoization if they use
optional chains in manual dependencies.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34503).
* #34689
* __->__ #34503
The View Transition docs were unclear about this but apparently the
`finished` promise never settles if the animation never started. So if
there's an error that rejects the `ready` promise, we'll never run the
clean up which can cause it to stall.
Fixes#34662.
However, ultimately that is caused by Chrome stalling our default
`onDefaultTransitionIndicator` but it should be unblocked after 10
seconds, not a minute.
Follow up to #34649. This adds the compiler rules back so they can be
opted-in 6.1.0, but aren't included in the presets as that would be a
breaking change.
Called Before:
> `logEvent` is a function created with React Hook "useEffectEvent", and
can only be called from the same component.
Called After:
> `logEvent` is a function created with React Hook "useEffectEvent", and
can only be called from Effects and Effect Events in the same component.
Referenced Before:
> `logEvent` is a function created with React Hook "useEffectEvent", and
can only be called from the same component. They cannot be assigned to
variables or passed down.
Referenced After:
> `logEvent` is a function created with React Hook "useEffectEvent", and
can only be called from Effects and Effect Events in the same component.
It cannot be assigned to a variable or passed down.
Reset EventTime when clearing timers. We need to track repeat updates
separately.
Typically we always reset all timers when we've logged an update. The
same update shouldn't be logged again.
I was trying to be clever and not reset the XEventTime because we also
need the timestamp to know if it's a repeat event. However, because of
this it looked like we had an event schedule an update even after we had
reset them.
This always resets the XEventTime to -1.1 and then stashes the old time
on EventRepeatTime which is our indication whether the next update was a
repeat of the old event.
---------
Co-authored-by: Ruslan Lesiutin <28902667+hoxyq@users.noreply.github.com>
Co-authored-by: Ricky <rickhanlonii@gmail.com>
Like in the diff below, we can read from the shared configuration to
check exhaustive deps.
I allow the classic additionalHooks configuration to override it so that
this change
is backwards compatible.
--
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34637).
* __->__ #34637
* #34497
We need to be able to specify additional effect hooks for the
RulesOfHooks lint rule
in order to allow useEffectEvent to be called by custom effects.
ExhaustiveDeps
does this with a regex suppplied to the rule, but that regex is not
accessible from
other rules.
This diff introduces a `react-hooks` entry you can put in the eslint
settings that
allows you to specify custom effect hooks and share them across all
rules.
This works like:
```
{
settings: {
'react-hooks': {
additionalEffectHooks: string,
},
},
}
```
The next diff allows useEffect to read from the same configuration.
----
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34497).
* #34637
* __->__ #34497
<!--
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?
-->
Added `<ViewTransition>` for when the "Show Internals" button is toggled
for a basic fade transition. Additionally added a transition for when
tabs are expanded in the advanced view of the Compiler Playground to
display a smoother show/hide animation.
## 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.
-->
https://github.com/user-attachments/assets/c706b337-289e-488d-8cd7-45ff1d27788d
We've observed some scenarios, where cascading update happens in an
effect that was shorter than 0.05ms. In this case, this effect won't be
displayed on a timeline, because of the threshold that we are using, but
it would be shown in entry properties or in a stack trace.
To avoid confusion, we should always log such effects.
Validated via manually changing the threshold to 100ms+ and observing
that only effects that triggered an update are visible on a timeline.
Otherwise, when a context is propagated into an Activity (or Suspense)
this will leave work behind on the Offscreen component itself. Which
will cause an extra unnecessary render and commit pass just to figure
out that we're still defering it to idle.
This is because lazy context propagation, when calling to schedule some
work walks back up the tree all the way to the root. This is usually
fine for other nodes since they'll recompute their remaining child lanes
on the way up. However, for the Offscreen component we'll have already
computed it. We need to set it after propagation to ensure it gets
reset.
We selected the root. This means that we're currently viewing the
Transition that rendered the whole screen. In laymans terms this is
really "Initial Paint". Once we add subtree selection, then the
equivalent should be called "Transition" since in that case it's really
about a Transition within the page. So if you've selected an Activity
tree this should be called "Transition".
Once we add the environment support to the timeline. The first entry on
the timeline should also be called "Initial Paint" when you haven't
selected an Activity and "Transition" when you have.
Technically they're both meant to be "Transition" but nobody thinks of
initial load as a "Transition" from the previous MPA page.
<img width="1214" height="419" alt="Screenshot 2025-09-29 at 5 18 58 PM"
src="https://github.com/user-attachments/assets/cae263e3-133c-4fa9-9587-a7b2344199f4"
/>
If I can scroll the document due to it overflowing, I should be able to
scroll the suspense tab as much. The real rect for the root when it's
the document is really the full scroll height.
This doesn't fully eliminate the need to do recursive bounding boxes for
the root since it's still possible to have the rects overflow. E.g. if
they're currently resuspended or inside nested scrolls.
~However, maybe we should have the actual paintable root rect just be
this rectangle instead of including the recursive ones.~ Actually never
mind. The root really represents the Transition so it doesn't make sense
to give it any specific rectangle. It's rather the whole background.
This brings the Suspense boundary that's switching into view so that
when you play the loading sequence you can see how it plays out.
Otherwise it's really hard to find where things are changing.
This assumes we'll also scroll synchronize the suspense tab which will
bring it into view there too.
## Summary
Experimentation has completed for this at Meta and we've observed
positive impact on key React Native surfaces.
## How did you test this change?
yarn flow fabric
This was merged into the 19.1.1 patch release branch in
https://github.com/facebook/react/pull/33972 but we never upstreamed it
to main. This should merge to main to make it easier to sync versions to
RN after future releases.
---------
Co-authored-by: Riccardo Cipolleschi <cipolleschi@meta.com>
<!--
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?
-->
Utilized `<ViewTransition>` to introduce a sliding animation upon
switching between the Output and SourceMap tabs in the default
playground view.
## 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.
-->
https://github.com/user-attachments/assets/1ac93482-8104-4f9a-887e-6adca3537dca
<!--
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?
-->
Introduced `<ViewTransition>` to the React Compiler Playground. Added an
initial animation on the config panel opening/closing to allow for a
smoother visual experience. Previously, the panel would flash in and out
of the screen upon open/close.
## 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.
-->
https://github.com/user-attachments/assets/9dc77a6b-d4a5-4a7a-9d81-007ebb55e8d2
When you double click it will hide or show by jumping to the selected
index or one step before the selected.
Let's you go from a suspense boundary into the timeline to find its
position. I also highlight the step in the timeline when you hover the
rect.
This only works if it's in the selected root but all of those should be
merged into one single timeline.
One thing that's weird about the SuspenseNodes now is that they
sometimes gets deleted but not always when they're resupended. Nested
ones maybe? This means that if you double click to hide it, you can't
double click again to show it. This seems like an unrelated bug that we
should fix.
We could potentially repurpose the existing "Suspend" button in the
toolbar to do this too, or maybe add another icon there.
Stacked on #34625.
This is a nice way to step through the timeline and simulate the visuals
on screen as you do it. It's also convenient to step through one at a
time, especially with the forwards button.
However, the secondary purpose of this is that it helps anchor the UI
visually as something like a timeline like in a video so that the
timeline itself becomes more identifiable.
https://github.com/user-attachments/assets/cb367c8e-9efb-4a00-a58e-4579be20beb8
The settings dialog appears on all tabs and should be reachable from
Suspense tab too. It's a bit weird because it's not contextual to the
tab and it shows you whatever your last settings tab was opened. Maybe
it should default to opening to the current tab's settings?
There aren't any Suspense specific settings yet but there definitely
will be. We could move the "Show all" into settings but it might be
frequently that you want to check why something isn't suspending a
Suspense boundary or test SSR streaming.
However, the general settings still apply to the Suspense tab. E.g.
switching dark/light mode.
<img width="857" height="233" alt="Screenshot 2025-09-27 at 12 35 05 PM"
src="https://github.com/user-attachments/assets/4a38e94f-2074-4dce-906b-9a1c40bccb9b"
/>
When forcing suspense/error we're doing that by scheduling a sync update
on the fiber. Resuspending a Suspense boundary can only happen sync
update so that makes sense. Erroring also forces a sync commit. This
means that no View Transitions fire.
However, unsuspending (and dismissing an error dialog) can be async so
the reveal should be able to be async.
This adds another hook for scheduling using the Retry lane. That way
when you play through a reveal sequence of Suspense boundaries (like
playing through the timeline), it'll run the animations that would've
ran during a loading sequence.
It's possible for the children to overflow the bounding rect of the root
in general when they overflow in the DOM. However even when it doesn't
overflow in the DOM, the bounding rect of the root can shrink while the
content is suspended. In fact, it's very likely.
Originally I thought we didn't need to consider this recursively because
document scrolling takes absolute positioned content into account but
because we're using nested overflow scrolling, we have to manually
compute this.
One thing that always bothered me is that the collapse buttons on either
side of the toolbar looks like left/right buttons which would conflict
with some steps buttons I plan to add. Another issue is that we'll need
to add more tool buttons to the top and probably eventually a Search
field. Ideally this whole section should line up vertically with the
height of the title row.
I also realized that all UIs that have some kind of timeline control
(and play/pause/skip) do that in the bottom below the content. E.g.
music players and video players all do that. We're better off playing
into that structure since that's the UI analogy we're going for here.
Makes it clearer what the weird timeline is for.
By moving it to the bottom it also frees up the top for the collapse
buttons and more controls.
__Horizontal__
<img width="794" height="809" alt="Screenshot 2025-09-26 at 3 40 35 PM"
src="https://github.com/user-attachments/assets/dacad9c4-d52f-4b66-9585-5cc74f230e6f"
/>
__Vertical__
<img width="570" height="812" alt="Screenshot 2025-09-26 at 3 40 53 PM"
src="https://github.com/user-attachments/assets/db225413-849e-46f1-b764-8fbd08b395c4"
/>
As titled. This adds dev-only debugging information to Fizz / Flight
that could be used for tracking Promise's stack traces in "suspended by"
section of DevTools.
Bumps `useEffectEvent` from `@experimental` to `@canary`. Removes the
`experimental_` prefix from the export.
## TODO
- [ ] Update useEffectEvent reference page and Canary badging in docs:
https://github.com/reactjs/react.dev/pull/8025
Tracks the environment names of the I/O in each SuspenseNode and sent it
to the front end when the suspenders change.
In the front end, every child boundary should really be treated as it
has all environment names of the parents too since they're blocked by
the parent too. We could do this tracking on backend but if there's ever
one added on the root would need to be send for every child.
This lets us highlight which subtrees are blocked by content on the
server.
---------
Co-authored-by: Sebastian "Sebbie" Silbermann <silbermann.sebastian@gmail.com>
When there are no named Activities we should hide the tree side panel
(and the button to show it). Since it's not implemented yet there are
never any ones so it's always hidden.
In Fizz and Fiber we emit hints for suspensey images and CSS as soon as
we discover them during render. At the beginning of the stream. This
adds a similar capability when a Host Component is known to be a Host
Component during the Flight render.
The client doesn't know that these resources are in the payload until it
parses that particular component which is lazy. So they need to be
hoisted with hints. We detect when these are rendered during Flight and
add them as hints. That allows you to consume a Flight payload to
preload prefetched content without having to render it.
`<link rel="preload">` can be hoisted more or less as is.
`<link rel="stylesheet">` we preload but we don't actually insert them
anywhere until they're rendered. We do these even for non-suspensey
stylesheets since we know that when they're rendered they're going to
start loading even if they're not immediately used. They're never lazy.
`<img src>` we only preload if they follow the suspensey image pattern
since otherwise they may be more lazy e.g. by if they're in the
viewport. We also skip if they're known to be inside `<picture>`. Same
as Fizz. Ideally this would preload the other `<source>` but it's
tricky.
The downside of this is that you might conditionally render something in
only one branch given a client component. However, in that case you're
already eagerly fetching the server component's data in that branch so
it's not too much of a stretch that you want to eagerly fetch the
corresponding resources as well. If you wanted it to be lazy, you
should've done a lazy fetch of the RSC.
We don't collect hints when any of these are wrapped in a Client
Component. In those cases you might want to add your own preload to a
wrapper Shared Component.
Everything is skipped if it's known to be inside `<noscript>`.
Note that the format context is approximate (see #34601) so it's
possible for these hints to overfetch or underfetch if you try to trick
it. E.g. by rendering Server Components inside a Client Component that
renders `<noscript>`.
---------
Co-authored-by: Josh Story <josh.c.story@gmail.com>
There was a bug in the Compiler Playground related to the "Show
Internals" toggle due to a useEffect that was causing the tab names to
flicker from a rerender. Rewritten instead with a `<Suspense>` boundary
+ `use`.
Flight doesn't have any semantically sound notion of a parent context.
That's why we removed Server Context. Each root can really start
anywhere in the tree when you refetch subtrees. Additionally when you
dedupe elements they can end up in multiple different parent contexts.
However, we do have a DEV only version of this with debugTask being
tracked for the nearest parent element to track the context of
properties inside of it.
To apply certain DOM specific hints and optimizations when you render
host components we need some information of the context. This is usually
very local so doesn't suffer from the likelihood that you refetch in the
middle. We'll also only use this information for optimistic hints and
not hard semantics so getting it wrong isn't terrible.
```
<picture>
<img />
</picture>
<noscript>
<p>
<img />
</p>
</noscript>
```
For example, in these cases we should exclude preloading the image but
we have to know if that's the scope we're in.
We can easily get this wrong if they're split or even if they're wrapped
in client components that we don't know about like:
```
<NoScript>
<p>
<img />
</p>
</NoScript>
```
However, getting it wrong in either direction is not the end of the
world. It's about covering the common cases well.
We should favor outlining a boundary if it contains Suspensey CSS or
Suspensey Images since then we can load that content separately and not
block the main content. This also allows us to animate the reveal.
For example this should be able to animate the reveal even though the
actual HTML content isn't large in this case it's worth outlining so
that the JS runtime can choose to animate this reveal.
```js
<ViewTransition>
<Suspense>
<img src="..." />
</Suspense>
</ViewTransition>
```
For Suspensey Images, in Fizz, we currently only implement the suspensey
semantics when a View Transition is running. Therefore the outlining
only applies if it appears inside a Suspense boundary which might
animate. Otherwise there's no point in outlining. It is also only if the
Suspense boundary itself might animate its appear and not just any
ViewTransition. So the effect is very conservative.
For CSS it applies even without ViewTransition though, since it can help
unblock the main content faster.
This PR ensures that server components are reliably included in the
DevTools component tree, even if debug info is received delayed, e.g.
when using a debug channel. The fix consists of three parts:
- We must not unset the debug chunk before all debug info entries are
resolved.
- We must ensure that the "RSC Stream" IO debug info entry is pushed
last, after all other entries were resolved.
- We need to transfer the debug info from blocked element chunks onto
the lazy node and the element.
Ideally, we wouldn't even create a lazy node for blocked elements that
are at the root of the JSON payload, because that would basically wrap a
lazy in a lazy. This optimization that ensures that everything around
the blocked element can proceed is only needed for nested elements.
However, we also need it for resolving deduped references in blocked
root elements, unless we adapt that logic, which would be a bigger lift.
When reloading the Flight fixture, the component tree is now displayed
deterministically. Previously, it would sometimes omit synchronous
server components.
<img width="306" height="565" alt="complete"
src="https://github.com/user-attachments/assets/db61aa10-1816-43e6-9903-0e585190cdf1"
/>
---------
Co-authored-by: Sebastian Markbage <sebastian@calyptus.eu>
We previously always generated import statements for any modules that
had to be required, notably the `import {c} from
'react/compiler-runtime'` for the memo cache function. However, this
obviously doesn't work when the source is using commonjs. Now we check
the sourceType of the module and generate require() statements if the
source type is 'script'.
I initially explored using
https://babeljs.io/docs/babel-helper-module-imports, but the API design
was unfortunately not flexible enough for our use-case. Specifically,
our pipeline is as follows:
* Compile individual functions. Generate candidate imports,
pre-allocating the local names for those imports.
* If the file is compiled successfully, actually add the imports to the
program.
Ie we need to pre-allocate identifier names for the imports before we
add them to the program — but that isn't supported by
babel-helper-module-imports. So instead we generate our own require()
calls if the sourceType is script.
@eps1lon flagged this case. Inlined useCallback has an extra LoadLocal
indirection which caused us not to add a name. While I was there I added
some extra checks to make sure we don't generate names for a given node
twice (just in case).
Stacked on #34546.
Same as #34538 but for gestures.
Includes various fixes.
This shows how it ends with a Transition when you release in the
committed state. Note how the Animation of the Gesture continues until
the Transition is done so that the handoff is seamless.
<img width="853" height="134" alt="Screenshot 2025-09-20 at 7 37 29 PM"
src="https://github.com/user-attachments/assets/6192a033-4bec-43b9-884b-77e3a6f00da6"
/>
This helper weirdly doesn't include the sync lane.
Everywhere we use it we have to check the sync lane separately. We can
simplify things by simply including the sync lane.
This fixes a lack of optimization because we should not check the store
consistency for a `flushSync` render.
d91d28c8ba/packages/react-reconciler/src/ReactFiberHooks.js (L1691-L1693)
If there is a large owner stack, we could potentially spam multiple
fetch requests for the same source map. This adds a simple deduplication
logic, based on URL.
Also, this adds a timeout of 60 seconds to all fetch requests initiated
by fileFetcher content script.
The root instance doesn't have a canonical property so we were not
returning a public instance that we can call compareDocumentPosition on
when a Fragment had no other host parent in Fabric. In this case we need
to get the ReactNativeElement from the ReactNativeDocument.
I've also added test coverage for this case in DOM for consistency,
though it was already working there because we use DOM elements as root.
This same test will be copied to RN using Fantom.
Below is a list of all new features, APIs, and bug fixes.
Read the [React 19.2 release post](https://react.dev/blog/2025/10/01/react-19-2) for more information.
### New React Features
- [`<Activity>`](https://react.dev/reference/react/Activity): A new API to hide and restore the UI and internal state of its children.
- [`useEffectEvent`](https://react.dev/reference/react/useEffectEvent) is a React Hook that lets you extract non-reactive logic into an [Effect Event](https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event).
- [`cacheSignal`](https://react.dev/reference/react/cacheSignal) (for RSCs) lets your know when the `cache()` lifetime is over.
- [React Performance tracks](https://react.dev/reference/developer-tooling/react-performance-tracks) appear on the Performance panel’s timeline in your browser developer tools
### New React DOM Features
- Added resume APIs for partial pre-rendering with Web Streams:
- [`resume`](https://react.dev/reference/react-dom/server/resume): to resume a prerender to a stream.
- [`resumeAndPrerender`](https://react.dev/reference/react-dom/static/resumeAndPrerender): to resume a prerender to HTML.
- Added resume APIs for partial pre-rendering with Node Streams:
- [`resumeToPipeableStream`](https://react.dev/reference/react-dom/server/resumeToPipeableStream): to resume a prerender to a stream.
- [`resumeAndPrerenderToNodeStream`](https://react.dev/reference/react-dom/static/resumeAndPrerenderToNodeStream): to resume a prerender to HTML.
- Updated [`prerender`](https://react.dev/reference/react-dom/static/prerender) APIs to return a `postponed` state that can be passed to the `resume` APIs.
### Notable changes
- React DOM now batches suspense boundary reveals, matching the behavior of client side rendering. This change is especially noticeable when animating the reveal of Suspense boundaries e.g. with the upcoming `<ViewTransition>` Component. React will batch as much reveals as possible before the first paint while trying to hit popular first-contentful paint metrics.
- Add Node Web Streams (`prerender`, `renderToReadableStream`) to server-side-rendering APIs for Node.js
- Use underscore instead of `:` IDs generated by useId
### All Changes
#### React
-`<Activity />` was developed over many years, starting before `ClassComponent.setState` (@acdlite@sebmarkbage and many others)
- Stringify context as "SomeContext" instead of "SomeContext.Provider" (@kassens [#33507](https://github.com/facebook/react/pull/33507))
- Include stack of cause of React instrumentation errors with `%o` placeholder (@eps1lon [#34198](https://github.com/facebook/react/pull/34198))
- Fix infinite `useDeferredValue` loop in popstate event (@acdlite [#32821](https://github.com/facebook/react/pull/32821))
- Fix a bug when an initial value was passed to `useDeferredValue` (@acdlite [#34376](https://github.com/facebook/react/pull/34376))
- Fix a crash when submitting forms with Client Actions (@sebmarkbage [#33055](https://github.com/facebook/react/pull/33055))
- Hide/unhide the content of dehydrated suspense boundaries if they resuspend (@sebmarkbage [#32900](https://github.com/facebook/react/pull/32900))
- Avoid stack overflow on wide trees during Hot Reload (@sophiebits [#34145](https://github.com/facebook/react/pull/34145))
- Improve Owner and Component stacks in various places (@sebmarkbage, @eps1lon: [#33629](https://github.com/facebook/react/pull/33629), [#33724](https://github.com/facebook/react/pull/33724), [#32735](https://github.com/facebook/react/pull/32735), [#33723](https://github.com/facebook/react/pull/33723))
- Block on Suspensey Fonts during reveal of server-side-rendered content (@sebmarkbage [#33342](https://github.com/facebook/react/pull/33342))
- Use underscore instead of `:` for IDs generated by `useId` (@sebmarkbage, @eps1lon: [#32001](https://github.com/facebook/react/pull/32001), [https://github.com/facebook/react/pull/33342](https://github.com/facebook/react/pull/33342)[#33099](https://github.com/facebook/react/pull/33099), [#33422](https://github.com/facebook/react/pull/33422))
- Stop warning when ARIA 1.3 attributes are used (@Abdul-Omira [#34264](https://github.com/facebook/react/pull/34264))
- Allow `nonce` to be used on hoistable styles (@Andarist [#32461](https://github.com/facebook/react/pull/32461))
- Warn for using a React owned node as a Container if it also has text content (@sebmarkbage [#32774](https://github.com/facebook/react/pull/32774))
- s/HTML/text for for error messages if text hydration mismatches (@rickhanlonii [#32763](https://github.com/facebook/react/pull/32763))
- Fix a bug with `React.use` inside `React.lazy`\-ed Component (@hi-ogawa [#33941](https://github.com/facebook/react/pull/33941))
- Enable the `progressiveChunkSize` option for server-side-rendering APIs (@sebmarkbage [#33027](https://github.com/facebook/react/pull/33027))
- Fix a bug with deeply nested Suspense inside Suspense fallback when server-side-rendering (@gnoff [#33467](https://github.com/facebook/react/pull/33467))
- Avoid hanging when suspending after aborting while rendering (@gnoff [#34192](https://github.com/facebook/react/pull/34192))
- Add Node Web Streams to server-side-rendering APIs for Node.js (@sebmarkbage [#33475](https://github.com/facebook/react/pull/33475))
#### React Server Components
- Preload `<img>` and `<link>` using hints before they're rendered (@sebmarkbage [#34604](https://github.com/facebook/react/pull/34604))
- Log error if production elements are rendered during development (@eps1lon [#34189](https://github.com/facebook/react/pull/34189))
- Fix a bug when returning a Temporary reference (e.g. a Client Reference) from Server Functions (@sebmarkbage [#34084](https://github.com/facebook/react/pull/34084), @denk0403 [#33761](https://github.com/facebook/react/pull/33761))
- Pass line/column to `filterStackFrame` (@eps1lon [#33707](https://github.com/facebook/react/pull/33707))
- Support Async Modules in Turbopack Server References (@lubieowoce [#34531](https://github.com/facebook/react/pull/34531))
- Add support for .mjs file extension in Webpack (@jennyscript [#33028](https://github.com/facebook/react/pull/33028))
- Fix a wrong missing key warning (@unstubbable [#34350](https://github.com/facebook/react/pull/34350))
- Make console log resolve in predictable order (@sebmarkbage [#33665](https://github.com/facebook/react/pull/33665))
#### React Reconciler
- [createContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L255-L261) and [createHydrationContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L305-L312) had their parameter order adjusted after `on*` handlers to account for upcoming experimental APIs
* Checking for higher order functions acting as factories for components/hooks
*/
@@ -669,6 +674,21 @@ export enum ErrorCategory {
FBT='FBT',
}
exportenumLintRulePreset{
/**
* Rules that are stable and included in the `recommended` preset.
*/
Recommended='recommended',
/**
* Rules that are more experimental and only included in the `recommended-latest` preset.
*/
RecommendedLatest='recommended-latest',
/**
* Rules that are disabled.
*/
Off='off',
}
exporttypeLintRule={
// Stores the category the rule corresponds to, used to filter errors when reporting
category: ErrorCategory;
@@ -689,15 +709,14 @@ export type LintRule = {
description: string;
/**
* If true, this rule will automatically appear in the default, "recommended" ESLint
* rule set. Otherwise it will be part of an `allRules` export that developers can
* use to opt-in to showing output of all possible rules.
* Configures the preset in which the rule is enabled. If 'off', the rule will not be included in
* any preset.
*
* NOTE: not all validations are enabled by default! Setting this flag only affects
* whether a given rule is part of the recommended set. The corresponding validation
* also should be enabled by default if you want the error to actually show up!
*/
recommended: boolean;
preset: LintRulePreset;
};
constRULE_NAME_PATTERN=/^[a-z]+(-[a-z]+)*$/;
@@ -720,7 +739,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'automatic-effect-dependencies',
description:
'Verifies that automatic effect dependencies are compiled if opted-in',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.CapitalizedCalls:{
@@ -730,7 +749,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'capitalized-calls',
description:
'Validates against calling capitalized functions/methods instead of using JSX',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.Config:{
@@ -739,7 +758,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
severity: ErrorSeverity.Error,
name:'config',
description:'Validates the compiler configuration options',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.EffectDependencies:{
@@ -748,7 +767,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
severity: ErrorSeverity.Error,
name:'memoized-effect-dependencies',
description:'Validates that effect dependencies are memoized',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.EffectDerivationsOfState:{
@@ -758,7 +777,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'no-deriving-state-in-effects',
description:
'Validates against deriving values from state in an effect',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.EffectSetState:{
@@ -768,7 +787,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'set-state-in-effect',
description:
'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.ErrorBoundaries:{
@@ -778,7 +797,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'error-boundaries',
description:
'Validates usage of error boundaries instead of try/catch for errors in child components',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.Factories:{
@@ -789,7 +808,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
description:
'Validates against higher order functions defining nested components or hooks. '+
'Components and hooks should be defined at the module level',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.FBT:{
@@ -798,7 +817,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
severity: ErrorSeverity.Error,
name:'fbt',
description:'Validates usage of fbt',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.Fire:{
@@ -807,7 +826,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
severity: ErrorSeverity.Error,
name:'fire',
description:'Validates usage of `fire`',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.Gating:{
@@ -817,7 +836,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'gating',
description:
'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.Globals:{
@@ -828,7 +847,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
description:
'Validates against assignment/mutation of globals during render, part of ensuring that '+
'[side effects must render outside of render](https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.Hooks:{
@@ -842,7 +861,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
* We need to dedeupe these (moving the remaining bits into the compiler) and then enable
* this rule.
*/
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.Immutability:{
@@ -852,7 +871,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'immutability',
description:
'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.Invariant:{
@@ -861,7 +880,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
severity: ErrorSeverity.Error,
name:'invariant',
description:'Internal invariants',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.PreserveManualMemo:{
@@ -873,7 +892,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
'Validates that existing manual memoized is preserved by the compiler. '+
'React Compiler will only compile components and hooks if its inference '+
'[matches or exceeds the existing manual memoization](https://react.dev/learn/react-compiler/introduction#what-should-i-do-about-usememo-usecallback-and-reactmemo)',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.Purity:{
@@ -883,7 +902,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'purity',
description:
'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.Refs:{
@@ -893,7 +912,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'refs',
description:
'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.RenderSetState:{
@@ -903,7 +922,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'set-state-in-render',
description:
'Validates against setting state during render, which can trigger additional renders and potential infinite render loops',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.StaticComponents:{
@@ -913,7 +932,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'static-components',
description:
'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.Suppression:{
@@ -922,7 +941,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
severity: ErrorSeverity.Error,
name:'rule-suppression',
description:'Validates against suppression of other rules',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.Syntax:{
@@ -931,7 +950,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
severity: ErrorSeverity.Error,
name:'syntax',
description:'Validates against invalid syntax',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.Todo:{
@@ -940,7 +959,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
severity: ErrorSeverity.Hint,
name:'todo',
description:'Unimplemented features',
recommended: false,
preset: LintRulePreset.Off,
};
}
caseErrorCategory.UnsupportedSyntax:{
@@ -950,7 +969,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'unsupported-syntax',
description:
'Validates against syntax that we do not plan to support in React Compiler',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.UseMemo:{
@@ -960,7 +979,17 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'use-memo',
description:
'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
recommended: true,
preset: LintRulePreset.Recommended,
};
}
caseErrorCategory.VoidUseMemo:{
return{
category,
severity: ErrorSeverity.Error,
name:'void-use-memo',
description:
'Validates that useMemos always return a value. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
preset: LintRulePreset.RecommendedLatest,
};
}
caseErrorCategory.IncompatibleLibrary:{
@@ -970,7 +999,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name:'incompatible-library',
description:
'Validates against usage of libraries which are incompatible with memoization (manual or automatic)',
`"Error: Could not validate environment config. Update React Compiler config to fix the error. Validation error: Expected boolean, received number at "validateHooksUsage"."`,
`"Error: Could not validate environment config. Update React Compiler config to fix the error. Validation error: Invalid input: expected boolean, received number at "validateHooksUsage"."`,
`"Error: Could not validate environment config. Update React Compiler config to fix the error. Validation error: autodepsIndex must be > 0 at "inferEffectDependencies[0].autodepsIndex"."`,
`"Error: Could not validate environment config. Update React Compiler config to fix the error. Validation error: AutodepsIndex must be > 0 at "inferEffectDependencies[0].autodepsIndex"."`,
Compilation Skipped: Existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `x.a.b?.c`, but the source dependencies were [x.a.b?.c.d?.e]. Inferred less specific property than source.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.