Commit Graph
1462 Commits
Author SHA1 Message Date
sebmarkbage dafa707da2 Log Performance Track Entries for View Transitions (#34510)
Stacked on #34509.

View Transitions introduces a bunch of new types of gaps in the commit
phase which needs to be logged differently in the performance track.

One thing that can happen is that a `flushSync` update forces the View
Transition to abort before it has started if it happens in the gap
before the transition is ready. In that case we log "Interrupted View
Transition".

Otherwise, when we're done in `startViewTransition` there's some work to
finalize the animations before the `ready` calllback. This is logged as
"Starting Animation".

Then there's a gap before the passive effects fire which we log as
"Animating". This can be long unless they're forced to flush early e.g.
due to another lane updating.

The "Animating" track should then pick up which doesn't do yet. This one
is tricky because this is after the actual commit phase and needs to be
interrupted by new renders which themselves can be suspended on the
animation finshing.

This PR is just a subset of all the cases. Will need a lot more work.

<img width="679" height="161" alt="Screenshot 2025-09-16 at 10 19 06 PM"
src="https://github.com/user-attachments/assets/0407372d-aaed-41f5-a262-059b2686ae87"
/>

DiffTrain build for [84af9085c1](https://github.com/facebook/react/commit/84af9085c11411e44cc5e5aee6cf00c02a78986e)
2025-09-17 10:13:03 -07:00
sebmarkbage 67d885809a Ensure Performance Track are Clamped and Don't overlap (#34509)
This simplifies the logic for clamping the start times of various
phases. Instead of checking in multiple places I ensure we compute a
value for each phase that is then clamped to the next phase so they
don't overlap. If they're zero they're not printed.

I also added a name for all the anonymous labels. Those are mainly
fillers for sync work that should be quick but it helps debugging if we
can name them.

Finally the real fix is to update the clamp time which previously could
lead to overlapping entries for consecutive updates when a previous
update never finalized before the next update.

DiffTrain build for [e3c9656d20](https://github.com/facebook/react/commit/e3c9656d20618ed321aea85cb3d844cbd1dce078)
2025-09-17 07:58:16 -07:00
josephsavona 82642d8e45 [compiler] Option to treat "set-" prefixed callees as setState functions (#34505)
Calling setState functions during render can lead to extraneous renders
or even infinite loops. We also have runtime detection for loops, but
static detection is obviously even better.

This PR adds an option to infer identifers as setState functions if both
the following conditions are met:
- The identifier is named starting with "set"
- The identifier is used as the callee of a call expression

By inferring values as SetState type, this allows our existing
ValidateNoSetStateInRender rule to flag calls during render, disallowing
examples like the following:

```js
function Component({setParentState}) {
  setParentState(...);
  ^^^^^^^^^^^^^^ Error: Cannot call setState in render
}
```

DiffTrain build for [7899729130](https://github.com/facebook/react/commit/78997291302c42b788dafa4c12da246e44be2dda)
2025-09-16 15:54:51 -07:00
sebmarkbage ed2bcf90b1 [Fiber] Wait for suspensey image in the viewport before starting an animation (#34500)
Stacked on #34486.

If we gave up on loading suspensey images for blocking the commit (e.g.
due to #34481), we can still block the view transition from committing
to allow an animation to include the image from the start.

At this point we have more information about the layout so we can
include only the images that are within viewport in the calculation
which may end up with a different answer.

This only applies when we attempt to run an animation (e.g. something
mutated inside a `<ViewTransition>` in a Transition). We could attempt a
`startViewTransition` if we gave up on the suspensey images just so that
we could block it even if no animation would be running.

However, this point the screen is frozen and you can no longer have sync
updates interrupt so ideally we would have already blocked the commit
from happening in the first place.

The reason to have two points where we block is that ideally we leave
the UI responsive while blocking, which blocking the commit does. In the
simple case of all images or a single image being within the viewport,
that's favorable. By combining the techniques we only end up freezing
the screen in the special case that we had a lot of images added outside
the viewport and started an animation with some image inside the
viewport (which presumably is about to finish anyway).

DiffTrain build for [348a4e2d44](https://github.com/facebook/react/commit/348a4e2d44fed940313d0657ee180083d12ffc04)
2025-09-15 15:17:38 -07:00
sebmarkbage 02ca3f9422 [Fiber] Don't wait on Suspensey Images if we guess that we don't load them all in time anyway (#34481)
Stacked on #34478.

In general we don't like to deal with timeouts in suspense world. We've
had that in the past but in general it doesn't work well because if you
have a timeout and then give up you made everything wait longer for no
benefit at the end. That's why the recommendation is to remove a
Suspense boundary if you expect it to be fast and add one if you expect
it to be slow. You have to estimate as the developer.

Suspensey images suffer from this same problem. We want to apply
suspensey images to as much as possible so that it's the default to
avoid flashing because if just a few images flash it's still almost as
bad as all of them. However, we do know that it's also very common to
use images and on a slow connection or many images, it's not worth it so
we have the timeout to eventually give up.

However, this means that in cases that are always slow or connections
that are always slow, you're always punished for no reason.

Suspensey images is mainly a polish feature to make high end experiences
on high end connections better but we don't want to unnecessarily punish
all slow connections in the process or things like lots of images below
the viewport.

This PR adds an estimate for whether or not we'll likely be able to load
all the images within the timeout on a high end enough connection. If
not, we'll still do a short suspend (unless we've already exceeded the
wait time adjusted for #34478) to allow loading from cache if available.

This estimate is based on two heuristics:

1) We compute an estimated bandwidth available on the current device in
mbps. This is computed from performance entries that have loaded static
resources already on the site. E.g. this can be other images, css, or
scripts. We see how long they took. If we don't have any entries (or if
they're all cross-origin in Safari) we fallback to
`navigator.connection.downlink` in Chrome or a 5mbps default in
Firefox/Safari.
2) To estimate how many bytes we'll have to download we use the
width/height props of the img tag if available (or a 100 pixel default)
times the device pixel ratio. We assume that a good img implementation
downloads proper resolution image for the device and defines a
width/height up front to avoid layout trash. Then we estimate that it
takes about 0.25 bytes per pixel which is somewhat conservative
estimate.

This is somewhat conservative given that the image could've been
preloaded and be better compressed.

So it really only kicks in for high end connections that are known to
load fast.

In a follow up, we can add an additional wait for View Transitions that
does the same estimate but only for the images that turn out to be in
viewport.

DiffTrain build for [ae22247dce](https://github.com/facebook/react/commit/ae22247dce1449574cd324cae0d8aa0d4824a937)
2025-09-15 13:16:12 -07:00
sebmarkbage eabed3aebd [Fiber] Adjust the suspensey image/css timeout based on already elapsed time (#34478)
Currently suspensey images doesn't account for how long we've already
been waiting. This means that you can for example wait for 300ms for the
throttle + 500ms for the images. If a Transition takes a while to
complete you can also wait that time + an additional 500ms for the
images.

This tracks the start time of a Transition so that we can count the
timeout starting from when the user interacted or when the last fallback
committed (which is where the 300ms throttle is computed from). Creating
a single timeline.

This also moves the timeout to a central place which I'll use in a
follow up.

DiffTrain build for [e3f191803c](https://github.com/facebook/react/commit/e3f191803cbe53df360b32f6735b05bb969c55cf)
2025-09-15 13:13:28 -07:00
josephsavona 3a661e1b87 [compiler]: add @tanstack/react-virtual to known incompatible libraries (#34493)
Replaces #31820. #34027 added a check for `@tanstack/react-table`, but
not `@tanstack/react-virtual`.
In our testing `@tanstack/react-virtual`'s `useVirtualizer` returns
functions that cannot be memoized, [this is also documented in the
community](https://github.com/TanStack/virtual/issues/736#issuecomment-3065658277).

DiffTrain build for [e12b0bdc3b](https://github.com/facebook/react/commit/e12b0bdc3b976cc2431ccf30126cf339be83720c)
2025-09-15 12:02:01 -07:00
rickhanlonii ea6e40ec0c Release Activity in Canary (#34374)
## Overview

This PR ships `<Activity />` to the `react@canary` release channel for
final feedback and prepare for semver stable release.

## What this means

Shipping `<Activity />` to canary means it has gone through extensive
testing in production, we are confident in the stability of the feature,
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 the feature.

## Why we follow the Canary Workflow

To prepare for semver stable, libraries should test canary features like
`<Activity>` 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 `<Activity />`.

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
Activity 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#activity)
blog post, and [the new docs for
`<Activity>`](https://react.dev/reference/react/Activity) for more info.

## TODO
- [x] Bump Activity docs to Canary
https://github.com/reactjs/react.dev/pull/7974

---------

Co-authored-by: Sebastian Sebbie Silbermann <sebastian.silbermann@vercel.com>

DiffTrain build for [68f00c901c](https://github.com/facebook/react/commit/68f00c901c05e3a91f6cc77b660bc2334700f163)
2025-09-12 09:54:23 -07:00
sebmarkbage 17f8109f8d [Fiber] Add context for the display: inline warning (#34461)
This warning doesn't execute within any particular context so doesn't
have a stack.

Pick the fiber of the child if it exists, otherwise the parent.

<img width="846" height="316" alt="Screenshot 2025-09-10 at 12 38 28 PM"
src="https://github.com/user-attachments/assets/7ab283a9-6e11-428d-9def-38f80ca958ef"
/>

DiffTrain build for [93d7aa69b2](https://github.com/facebook/react/commit/93d7aa69b29c20529c40cf64b0afdb5d51c9ddd1)
2025-09-12 09:04:24 -07:00
sebmarkbage 29c2cedbb3 [Flight][Fiber] Encode owner in the error payload in dev and use it as the Error's Task (#34460)
When we report an error we typically log the owner stack of the thing
that caught the error. Similarly we restore the `console.createTask`
scope of the catching component when we call `reportError` or
`console.error`.

We also have a special case if something throws during reconciliation
which uses the Server Component task as far as we got before we threw.

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactChildFiber.js#L1952-L1960

Chrome has since fixed it (on our request) that the Error constructor
snapshots the Task at the time the constructor was created and logs that
in `reportError`. This is a good thing since it means we get a coherent
stack. Unfortunately, it means that the fake Errors that we create in
Flight Client gets a snapshot of the task where they were created so
when they're reported in the console they get the root Task instead of
the Task of the handler of the error.

Ideally we'd transfer the Task from the server and restore it. However,
since we don't instrument the Error object to snapshot the owner and we
can't read the native Task (if it's even enabled on the server) we don't
actually have a correct snapshot to transfer for a Server Component
Error. However, we can use the parent's task for where the error was
observed by Flight Server and then encode that as a pseudo owner of the
Error.

Then we use this owner as the Task which the Error is created within.
Now the client snapshots that Task which is reported by `reportError` so
now we have an async stack for Server Component errors again. (Note that
this owner may differ from the one observed by `captureOwnerStack` which
gets the nearest Server Component from where it was caught. We could
attach the owner to the Error object and use that owner when calling
`onCaughtError`/`onUncaughtError`).

Before:

<img width="911" height="57" alt="Screenshot 2025-09-10 at 10 57 54 AM"
src="https://github.com/user-attachments/assets/0446ef96-fad9-4e17-8a9a-d89c334233ec"
/>

After:

<img width="910" height="128" alt="Screenshot 2025-09-10 at 11 06 20 AM"
src="https://github.com/user-attachments/assets/b30e5892-cf40-4246-a588-0f309575439b"
/>

Similarly, there are Errors and warnings created by ChildFiber itself.
Those execute in the scope of the general render of the parent Fiber.
They used to get the scope of the nearest client component parent (e.g.
div in this case) but that's the parent of the Server Component. It
would be too expensive to run every level of reconciliation in its own
task optimistically, so this does it only when we know that we'll throw
or log an error that needs this context. Unfortunately this doesn't
cover user space errors (such as if an iterable errors).

Before:

<img width="903" height="298" alt="Screenshot 2025-09-10 at 11 31 55 AM"
src="https://github.com/user-attachments/assets/cffc94da-8c14-4d6e-9a5b-bf0833b8b762"
/>

After:

<img width="1216" height="252" alt="Screenshot 2025-09-10 at 11 50
54 AM"
src="https://github.com/user-attachments/assets/f85f93cf-ab73-4046-af3d-dd93b73b3552"
/>

<img width="412" height="115" alt="Screenshot 2025-09-10 at 11 52 46 AM"
src="https://github.com/user-attachments/assets/a76cef7b-b162-4ecf-9b0a-68bf34afc239"
/>

DiffTrain build for [20e5431747](https://github.com/facebook/react/commit/20e5431747347796b3be8312e56cef655b26ef4d)
2025-09-12 09:01:49 -07:00
hoxyq 733b550162 [Reconciler] Set ProfileMode for Host Root Fiber by default in dev (#34432)
Requiring DevTools to be present for dev builds seems like an overkill,
let's enable the instrumentation by default.

Nothing changes for profiling or production artifacts.

DiffTrain build for [0e10ee906e](https://github.com/facebook/react/commit/0e10ee906e3ea55e4d717d4db498e1159235b06b)
2025-09-12 04:27:10 -07:00
hoxyq d67eddf18d [Tracks]: display method name and component name for updates in DEV (#34463)
For every "Update" entry we are going to add properties that will be
displayed when the user clicks on that entry: name of the method that
caused this first update and name of the component where this update
happened.

We could use the name of the component as a deeplink to React DevTools
components panel in the future, once we support stable identificators on
Fibers.

<img width="1444" height="530" alt="Screenshot 2025-09-10 at 18 31 10"
src="https://github.com/user-attachments/assets/7f9af037-2e7f-4e7b-9b7e-bf9f7d5a6e72"
/>
<img width="2088" height="530" alt="Screenshot 2025-09-10 at 18 24 21"
src="https://github.com/user-attachments/assets/f557a173-bd9b-43f7-9333-74066f433ced"
/>
<img width="2088" height="530" alt="Screenshot 2025-09-10 at 18 26 04"
src="https://github.com/user-attachments/assets/ff37d13f-bbe3-4f85-800e-81aa3aed7833"
/>

DiffTrain build for [0c813c528d](https://github.com/facebook/react/commit/0c813c528d78a7b1c831f758353416709630a104)
2025-09-12 03:41:00 -07:00
josephsavona fed06663f7 [compiler] More flexible/helpful lazy ref initialization (#34449)
Two small QoL improvements inspired by feedback:
* `if (ref.current === undefined) { ref.current = ... }` is now allowed.
* `if (!ref.current) { ref.current = ... }` is still disallowed, but we
emit an extra hint suggesting the `if (!ref.current == null)` pattern.

I was on the fence about the latter. We got feedback asking to allow `if
(!ref.current)` but if your ref stores a boolean value then this would
allow reading the ref in render. The unary form is also less precise in
general due to sketchy truthiness conversions. I figured a hint is a
good compromise.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34449).
* __->__ #34449
* #34424

DiffTrain build for [bd9e6e0bed](https://github.com/facebook/react/commit/bd9e6e0bed6aed479940b1cf891dde82ab224028)
2025-09-10 13:48:39 -07:00
poteto 0e51ebf78f [compiler] Allow setStates in use{Layout,Insertion}Effect where the set value is derived from a ref (#34462)
@stipsan found this issue where the compiler would bailout on the
`useLayoutEffect` examples in the React docs. While setState in an
effect is typically an anti-pattern due to the fact that it hurts
performance through cascading renders, the one scenario where it _is_
allowed is if the value being set flows from a ref.

DiffTrain build for [835b00908b](https://github.com/facebook/react/commit/835b00908b1b1c522323162b735a85c5f620ac81)
2025-09-10 12:07:47 -07:00
josephsavona 97ab71aa8a [compiler] Fix false positive hook return mutation error (#34424)
This was fun. We previously added the MaybeAlias effect in #33984 in
order to describe the semantic that an unknown function call _may_ alias
its return value in its result, but that we don't know this for sure. We
record mutations through MaybeAlias edges when walking backward in the
data flow graph, but downgrade them to conditional mutations. See the
original PR for full context.

That change was sufficient for the original case like

```js
const frozen = useContext();
useEffect(() => {
  frozen.method().property = true;
}, [...]);
```

But it wasn't sufficient for cases where the aliasing occured between
operands:

```js
const dispatch = useDispatch();
<div onClick={(e) => {
  dispatch(...e.target.value)
  e.target.value = ...;
}} />
```

Here we would record a `Capture dispatch <- e.target` effect. Then
during processing of the `event.target.value = ...` assignment we'd
eventually _forward_ from `event` to `dispatch` (along a MaybeAlias
edge). But in #33984 I missed that this forward walk also has to
downgrade to conditional.

In addition to that change, we also have to be a bit more precise about
which set of effects we create for alias/capture/maybe-alias. The new
logic is a bit clearer, I think:

* If the value is frozen, it's an ImmutableCapture edge
* If the values are mutable, it's a Capture
* If it's a context->context, context->mutable, or mutable->context,
count it as MaybeAlias.

DiffTrain build for [acada3035f](https://github.com/facebook/react/commit/acada3035fe2a0dacfafc0ad78914e77d11fb823)
2025-09-09 14:14:52 -07:00
josephsavona abd4b80d40 [compiler] Improve name hints for outlined functions (#34434)
The previous PR added name hints for anonymous functions, but didn't
handle the case of outlined functions. Here we do some cleanup around
function `id` and name hints:
* Make `HIRFunction.id` a ValidatedIdentifierName, which involved some
cleanup of the validation helpers
* Add `HIRFunction.nameHint: string` as a place to store the generated
name hints which are not valid identifiers
* Update Codegen to always use the `id` as the actual function name, and
only use nameHint as part of generating the object+property wrapper for
debug purposes.

This ensures we don't conflate synthesized hints with real function
names. Then, we also update OutlineFunctions to use the function name
_or_ the nameHint as the input to generating a unique identifier. This
isn't quite as nice as the object form since we lose our formatting, but
it's a simple step that gives more context to the developer than `_temp`
does.

Switching to output the object+property lookup form for outlined
functions is a bit more involved, let's do that in a follow-up.

DiffTrain build for [665de2ed28](https://github.com/facebook/react/commit/665de2ed283205fccecda649ae2d66f62983f15f)
2025-09-09 12:20:27 -07:00
mofeiZ 7f6493d906 [compiler] Fix false positive memo validation (alternative) (#34319)
Alternative to #34276

---
(Summary taken from @josephsavona 's #34276)
Partial fix for #34262. Consider this example:

```js
function useInputValue(input) {
  const object = React.useMemo(() => {
    const {value} = transform(input);
    return {value};
  }, [input]);
  return object;
}
```

React Compiler breaks this code into two reactive scopes:
* One for `transform(input)`
* One for `{value}`

When we run ValidatePreserveExistingMemo, we see that the scope for
`{value}` has the dependency `value`, whereas the original memoization
had the dependency `input`, and throw an error that the dependencies
didn't match.

In other words, we're flagging the fact that memoized _better than the
user_ as a problem. The more complete solution would be to validate that
there is a subgraph of reactive scopes with a single input and output
node, where the input node has the same dependencies as the original
useMemo, and the output has the same outputs. That is true in this case,
with the subgraph being the two consecutive scopes mentioned above.

But that's complicated. As a shortcut, this PR checks for any
dependencies that are defined after the start of the original useMemo.
If we find one, we know that it's a case where we were able to memoize
more precisely than the original, and we don't report an error on the
dependency. We still check that the original _output_ value is able to
be memoized, though. So if the scope of `object` were extended, eg with
a call to `mutate(object)`, then we'd still correctly report an error
that we couldn't preserve memoization.

Co-authored-by: Joe Savona <joesavona@fb.com>

DiffTrain build for [eda778b8ae](https://github.com/facebook/react/commit/eda778b8ae1698fec5fc84ca2530727df8b557b5)
2025-09-09 11:33:13 -07:00
josephsavona e026437175 [compiler] Option to infer names for anonymous functions (#34410)
Adds a `@enableNameAnonymousFunctions` feature to infer helpful names
for anonymous functions within components and hooks. The logic is
inspired by a custom Next.js transform, flagged to us by @eps1lon, that
does something similar. Implementing this transform within React
Compiler means that all React (Compiler) users can benefit from more
helpful names when debugging.

The idea builds on the fact that JS engines try to infer helpful names
for anonymous functions (in stack traces) when those functions are
accessed through an object property lookup:

```js
({'a[xyz]': () => {
  throw new Error('hello!')
} }['a[xyz]'])()

// Stack trace:
Uncaught Error: hello!
    at a[xyz] (<anonymous>:1:26) // <-- note the name here
    at <anonymous>:1:60
```

The new NameAnonymousFunctions transform is gated by the above flag,
which is off by default. It attemps to infer names for functions as
follows:

First, determine a "local" name:
* Assigning a function to a named variable uses the variable name.
`const f = () => {}` gets the name "f".
* Passing the function as an argument to a function gets the name of the
function, ie `foo(() => ...)` get the name "foo()", `foo.bar(() => ...)`
gets the name "foo.bar()". Note the parenthesis to help understand that
it was part of a call.
* Passing the function to a known hook uses the name of the hook,
`useEffect(() => ...)` uses "useEffect()".
* Passing the function as a JSX prop uses the element and attr name, eg
`<div onClick={() => ...}` uses "<div>.onClick".

Second, the local name is combined with the name of the outer
component/hook, so the final names will be strings like `Component[f]`
or `useMyHook[useEffect()]`.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34410).
* #34434
* __->__ #34410

DiffTrain build for [a9410fb487](https://github.com/facebook/react/commit/a9410fb487776339ec68e57a57a570be952ccad0)
2025-09-09 10:33:57 -07:00
josephsavona 866cba0b19 [compiler] Handle empty list of eslint suppression rules (#34323)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34323).
* #34276
* __->__ #34323

DiffTrain build for [3f2a42a5de](https://github.com/facebook/react/commit/3f2a42a5decc88551d34c96f3d031c316ac34f6a)
2025-09-08 10:39:24 -07:00
josephsavona a47f44721e [compiler] Add missing source locations to statements, expressions (#34406)
Adds missing locations to all the statement kinds that we produce in
codegenInstruction(), and adds generic handling of source locations for
the nodes produced by codegenInstructionValue(). There are definitely
some places where we are still missing a location, but this should
address some of the known issues we've seen such as missing location on
`throw`.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34406).
* #34394
* __->__ #34406
* #34346

DiffTrain build for [f5e96b9740](https://github.com/facebook/react/commit/f5e96b974073d3ba80dc844d095c49d5b019afe0)
2025-09-06 11:20:49 -07:00
poteto 118621b1d1 [compiler] Fix error description inconsistency (#34404)
Small fix to make all descriptions consistently printed with a single
period at the end.

Ran `grep -rn "description:" packages/babel-plugin-react-compiler/src
--include="*.ts" --exclude-dir="__tests__" | grep '\.\s*["\`]'` to find
all descriptions ending in a period and manually fixed them.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34404).
* #34409
* __->__ #34404

DiffTrain build for [80d7aa17ad](https://github.com/facebook/react/commit/80d7aa17ad42efccc0ff95d2a9147ac6efe74dd5)
2025-09-06 10:13:29 -07:00
poteto 10353d6050 [compiler] Migrate CompilerError.invariant to new CompilerDiagnostic infra (#34403)
Mechanical PR to migrate existing invariants to use the new
CompilerDiagnostic infra @josephsavona added. Will tackle the others at
a later time.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34403).
* #34409
* #34404
* __->__ #34403

DiffTrain build for [474f25842a](https://github.com/facebook/react/commit/474f25842a90f67a7aa8c6329afb5faec52181b6)
2025-09-06 10:04:20 -07:00
poteto 11a88173f5 [compiler] Derive ErrorSeverity from ErrorCategory (#34401)
With #34176 we now have granular lint rules created for each compiler
ErrorCategory. However, we had remnants of our old error severities
still in use which makes reporting errors quite clunky. Previously you
would need to specify both a category and severity which often ended up
being the same.

This PR moves severity definition into our rules which are generated
from our categories. For now I decided to defer "upgrading" categories
from a simple string to a sum type since we are only using severities to
map errors to eslint severity.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34401).
* #34409
* #34404
* #34403
* #34402
* __->__ #34401

DiffTrain build for [60d9b9740d](https://github.com/facebook/react/commit/60d9b9740d77bd2715f5f725245093a23f95e347)
2025-09-06 09:50:43 -07:00
josephsavona 7ac0c331c2 [compiler] Cleanup for @enablePreserveExistingMemoizationGuarantees (#34346)
I tried turning on `@enablePreserveExistingMemoizationGuarantees` by
default and cleaned up a couple small things:

* We emit freeze calls for StartMemoize deps but these had
ValueReason.Other so the message wasn't great. We now treat these like
other hook arguments.
* PruneNonEscapingScopes was being too aggressive in this mode and
memoizing even loads of globals. Switching to
MemoizationLevel.Conditional ensures we build a graph that connects
through to primitive-returning function calls, but doesn't unnecessarily
force memoization otherwise.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34346).
* #34347
* __->__ #34346

DiffTrain build for [2710795a1e](https://github.com/facebook/react/commit/2710795a1ed339764d2fa76b6d7bc94dded6ee60)
2025-09-03 21:37:11 -07:00
josephsavona 4a2aee93b0 [compiler] Fix for scopes with unreachable fallthroughs (#34335)
Fixes #34108. If a scope ends with with a conditional where some/all
branches exit via labeled break, we currently compile in a way that
works but bypasses memoization. We end up with a shape like

```js
let t0;
label: {
 if (changed) {
   ...
   if (cond) {
     t0 = ...;
     break label;
   }
   // we don't save the output if the break happens!
   t0 = ...;
   $[0] = t0;
 } else {
   t0 = $[0];
}
```

The fix here is to update AlignReactiveScopesToBlockScopes to take
account of breaks that don't go to the natural fallthrough. In this
case, we take any active scopes and extend them to start at least as
early as the label, and extend at least to the label fallthrough. Thus
we produce the correct:

```js
let t0;
if (changed) {
  label: {
    ...
    if (cond) {
      t0 = ...;
      break label;
    }
    t0 = ...;
  }
  // now the break jumps here, and we cache the value
  $[0] = t0;
} else {
  t0 = $[0];
}
```

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34335).
* #34347
* #34346
* #34343
* __->__ #34335

DiffTrain build for [5d64f74211](https://github.com/facebook/react/commit/5d64f742114203e4fbdd605ce398696d18901f35)
2025-09-03 17:51:03 -07:00
acdlite 12c6a751b3 Fix: uDV skipped initial value if earlier transition suspended (#34376)
Fixes a bug in useDeferredValue's optional `initialValue` argument. In
the regression case, if a new useDeferredValue hook is mounted while an
earlier transition is suspended, the `initialValue` argument of the new
hook was ignored. After the fix, the `initialValue` argument is
correctly rendered during the initial mount, regardless of whether other
transitions were suspended.

The culprit was related to the mechanism we use to track whether a
render is the result of a `useDeferredValue` hook: we assign the
deferred lane a TransitionLane, then entangle that lane with the
DeferredLane bit. During the subsequent render, we check for the
presence of the DeferredLane bit to determine whether to switch to the
final, canonical value.

But because transition lanes can themselves become entangled with other
transitions, the effect is that every entangled transition was being
treated as if it were the result of a `useDeferredValue` hook, causing
us to skip the initial value and go straight to the final one.

The fix I've chosen is to reserve some subset of TransitionLanes to be
used only for deferred work, instead of using entanglement. This is
similar to how retries are already implemented. Originally I tried not
to implement it this way because it means there are now slightly fewer
lanes allocated for regular transitions, but I underestimated how
similar deferred work is to retries; they end up having a lot of the
same requirements. Eventually it may be possible to merge the two
concepts.

DiffTrain build for [3302d1f791](https://github.com/facebook/react/commit/3302d1f791f3f1cf4e8cf69bee70ce5dab1b8436)
2025-09-03 16:37:25 -07:00
rickhanlonii 0c939fccd8 [flags] enable opt-in for enableDefaultTransitionIndicator (#34373)
So we can test the feature.

DiffTrain build for [3168e08f83](https://github.com/facebook/react/commit/3168e08f8389d258de9eb7c8d19b9d44a0f250f2)
2025-09-03 09:40:29 -07:00
hoxyq 87fce6e2f0 Performance Tracks: log properties diff for renders in DEV if no console task available (#34370)
React Native doesn't support `console.createTask` yet, but it does
support `performance.measure` and extensibility APIs for Performance
panel, including `detail.devtools` field.

Previously, this logic was gated with `if (__DEV__ && debugTask)`, now
`debugTask` is no longer required to log render. If there is no console
task, we will just call `performance.measure(...)`. The same pattern is
used in other reporters.

DiffTrain build for [2805f0ed9e](https://github.com/facebook/react/commit/2805f0ed9e702454527839c0076a9979553c2fd7)
2025-09-03 09:14:33 -07:00
eps1lon af3f7fe348 [Flight] Fix wrong missing key warning when static child is blocked (#34350)
DiffTrain build for [bb6f0c8d2f](https://github.com/facebook/react/commit/bb6f0c8d2f29754347db0ff28186dc89c128b6ca)
2025-09-01 02:10:05 -07:00
josephsavona 91c9f1803e [compiler] Detect known incompatible libraries (#34027)
A few libraries are known to be incompatible with memoization, whether
manually via `useMemo()` or via React Compiler. This puts us in a tricky
situation. On the one hand, we understand that these libraries were
developed prior to our documenting the [Rules of
React](https://react.dev/reference/rules), and their designs were the
result of trying to deliver a great experience for their users and
balance multiple priorities around DX, performance, etc. At the same
time, using these libraries with memoization — and in particular with
automatic memoization via React Compiler — can break apps by causing the
components using these APIs not to update. Concretely, the APIs have in
common that they return a function which returns different values over
time, but where the function itself does not change. Memoizing the
result on the identity of the function will mean that the value never
changes. Developers reasonable interpret this as "React Compiler broke
my code".

Of course, the best solution is to work with developers of these
libraries to address the root cause, and we're doing that. We've
previously discussed this situation with both of the respective
libraries:
* React Hook Form:
https://github.com/react-hook-form/react-hook-form/issues/11910#issuecomment-2135608761
* TanStack Table:
https://github.com/facebook/react/issues/33057#issuecomment-2840600158
and https://github.com/TanStack/table/issues/5567

In the meantime we need to make sure that React Compiler can work out of
the box as much as possible. This means teaching it about popular
libraries that cannot be memoized. We also can't silently skip
compilation, as this confuses users, so we need these error messages to
be visible to users. To that end, this PR adds:

* A flag to mark functions/hooks as incompatible
* Validation against use of such functions
* A default type provider to provide declarations for two
known-incompatible libraries

Note that Mobx is also incompatible, but the `observable()` function is
called outside of the component itself, so the compiler cannot currently
detect it. We may add validation for such APIs in the future.

Again, we really empathize with the developers of these libraries. We've
tried to word the error message non-judgementally, because we get that
it's hard! We're open to feedback about the error message, please let us
know.

DiffTrain build for [4082b0e7d3](https://github.com/facebook/react/commit/4082b0e7d3c042d49ef8987547b923051936956f)
2025-08-28 16:27:20 -07:00
poteto 790f9d1243 [eprh] Update installation instructions in readme (#34331)
Small PR to update our readme for eslint-plugin-react-hooks, to better
describe what a minimal but complete eslint config would look like.

DiffTrain build for [872b4fef6d](https://github.com/facebook/react/commit/872b4fef6ded18aa9bda5f7729340384a914ba7b)
2025-08-28 15:34:27 -07:00
josephsavona 5ad8789207 [compiler] Show a ref name hint when assigning to non-ref in a callback (#34298)
In #34125 I added a hint where if you assign to the .current property of
a frozen object, we suggest naming the variable as `ref` or `-Ref`.
However, the tracking for mutations that assign to .current specifically
wasn't propagated past function expression boundaries, which meant that
the hint only showed up if you mutated the ref in the main body of the
component/hook. That's less likely to happen since most folks know not
to access refs in render. What's more likely is that you'll (correctly)
assign a ref in an effect or callback, but the compiler will throw an
error. By showing a hint in this case we can help people understand the
naming pattern.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34298).
* #34276
* __->__ #34298

DiffTrain build for [8d7b5e4903](https://github.com/facebook/react/commit/8d7b5e490320732f40d9c3aa4590b5b0ae5116f5)
2025-08-27 17:12:11 -07:00
jackpope 7151d71ea5 Add scrollIntoView to fragment instances (#32814)
This adds `experimental_scrollIntoView(alignToTop)`. It doesn't yet
support `scrollIntoView(options)`.

Cases:
- No host children: Without host children, we represent the virtual
space of the Fragment by attempting to scroll to the nearest edge by
using its siblings. If the preferred sibling is not found, we'll try the
other side, and then the parent.
- 1 or more host children: In order to handle the case of children
spread between multiple scroll containers, we scroll to each child in
reverse order based on the `alignToTop` flag.

Due to the complexity of multiple scroll containers and dealing with
portals, I've added this under a separate feature flag with an
experimental prefix. We may stabilize it along with the other APIs, but
this allows us to not block the whole feature on it.

This PR was previously implementing a much more complex approach to
handling multiple scroll containers and portals. We're going to start
with the simple loop and see if we can find any concrete use cases where
that doesn't suffice. 01f31d4301 is the
diff between approaches here.

DiffTrain build for [3434ff4f4b](https://github.com/facebook/react/commit/3434ff4f4b89ad9388c6109312ef95c14652ae21)
2025-08-27 15:12:12 -07:00
poteto 4928606df6 [compiler] Emit better error for unsupported syntax this (#34322)
DiffTrain build for [bd5b1b7639](https://github.com/facebook/react/commit/bd5b1b7639b818a3fbd33ce83bf022a6f9f27b55)
2025-08-27 15:04:54 -07:00
poteto bab781cd27 [compiler] Validate against component/hook factories (#34305)
Previously, the compiler would incorrectly attempt to compile nested
components/hooks defined inside non-React functions. This would lead to
scope reference errors at runtime because the compiler would optimize
the nested React function without understanding its closure over the
parent function's variables.

This PR adds detection when non-React functions declare components or
hooks, and reports a clear error before compilation. I put this under a
new compiler flag defaulting to false. I'll run a test on this
internally first, but I expect we should be able to just turn it on in
both compiler (so we stop miscompiling) and linter.

Closes #33978

Playground example:
https://react-compiler-playground-git-pr34305-fbopensource.vercel.app/#N4Igzg9grgTgxgUxALhAejQAgAIDcCGANgJYAm+ALggHIQAiAngHb4C2xcRhDAwjApQSkeEVgAcITBEwpgA8jAASECAGswAHSkAPCTAqYAZlCZwKxSZgDmCCgEkmYqBQAU+AJSZgWzJjiSwAwB1GHwxMQQYTABeTBdPaIA+Lx9fPwCDAAt8JlJCBB5sphsYuITk7yY0tPwAOklCnJt4gG5U3wBfNqZ2zH4KWCqAHmJHZ0wGopto4CK8gqmEDsw0RO7O7tT+wcwQsIiYbo6QDqA

DiffTrain build for [b870042915](https://github.com/facebook/react/commit/b870042915c8a7cc1524feb7e0b5cbe7453a7648)
2025-08-27 11:05:50 -07:00
josephsavona a36444763f [compiler] Infer render helpers for additional validation (#33647)
We currently assume that any functions passes as props may be event
handlers or effect functions, and thus don't check for side effects such
as mutating globals. However, if a prop is a function that returns JSX
that is a sure sign that it's actually a render helper and not an event
handler or effect function. So we now emit a `Render` effect for any
prop that is a JSX-returning function, triggering all of our render
validation.

This required a small fix to InferTypes: we weren't correctly populating
the `return` type of function types during unification. I also improved
the printing of types so we can see the inferred return types.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33647).
* #33643
* #33650
* #33642
* __->__ #33647

DiffTrain build for [33a1095d72](https://github.com/facebook/react/commit/33a1095d724c5ad0a6238e03e04461b6df5e73e2)
2025-08-27 08:51:59 -07:00
unstubbable aaad082f0a [Flight] Don't drop debug info if there's only a readable debug channel (#34304)
When the Flight Client is waiting for pending debug chunks, it drops the
debug info if there is no writable side of the debug channel defined.
However, it should instead check if there's no readable side defined.

Fixing this is not only important for browser clients that don't want or
need a return channel, but it's also crucial for server-side rendering,
because the Node and Edge clients only accept a readable side of the
debug channel. So they can't even define a noop writable side as a
workaround.

DiffTrain build for [9c2e2b8475](https://github.com/facebook/react/commit/9c2e2b8475fb9d55fe47f55b007fba2d474e06f4)
2025-08-27 05:09:25 -07:00
unstubbable 621eb5e4ef [Flight] Wait for both streams to end before closing the response (#34301)
When a debug channel is defined, we must ensure that we don't close the
Flight Client's response when the debug channel's readable is done, but
the RSC stream is still flowing. Now, we wait for both streams to end
before closing the response.

DiffTrain build for [cacc20e37c](https://github.com/facebook/react/commit/cacc20e37c9ec320b5d2aa13f86cfc999d269d6b)
2025-08-26 08:48:56 -07:00
eps1lon 7b03e140c4 [Fizz] Skip past hidden inputs when attempting to hydrate hydration boundaries (#34302)
DiffTrain build for [4123f6b771](https://github.com/facebook/react/commit/4123f6b771bb71a2831b1c450c385c38530125a0)
2025-08-26 08:35:03 -07:00
josephsavona e0be527bfc [compiler] Script to produce markdown of lint rule docs (#34260)
The docs site is in a separate repo, but this gives us a semi-automated
way to update the docs about our lint rules. The script generates
markdown files from the rule definitions which we can then manually
copy/paste into the docs site somewhere. In the future we can automate
this fully.

DiffTrain build for [425ba0ad6d](https://github.com/facebook/react/commit/425ba0ad6d3ebd1779f6a658dcbf5c666d054948)
2025-08-22 10:06:12 -07:00
eps1lon a2b19a6a0b Add support for ARIA 1.3 attributes (#34264)
Co-authored-by: Abdulwahab Omira <abdulwahabomira@gmail.com>
Co-authored-by: Sebastian Sebbie Silbermann <sebastian.silbermann@vercel.com>

DiffTrain build for [698bb4deb7](https://github.com/facebook/react/commit/698bb4deb7c77010c040ac49630c26db94e6e28c)
2025-08-22 07:30:07 -07:00
josephsavona f7eb4653b7 [compiler] Aggregate error reporting, separate eslint rules (#34176)
NOTE: this is a merged version of @mofeiZ's original PR along with my
edits per offline discussion. The description is updated to reflect the
latest approach.

The key problem we're trying to solve with this PR is to allow
developers more control over the compiler's various validations. The
idea is to have a number of rules targeting a specific category of
issues, such as enforcing immutability of props/state/etc or disallowing
access to refs during render. We don't want to have to run the compiler
again for every single rule, though, so @mofeiZ added an LRU cache that
caches the full compilation output of N most recent files. The first
rule to run on a given file will cause it to get cached, and then
subsequent rules can pull from the cache, with each rule filtering down
to its specific category of errors.

For the categories, I went through and assigned a category roughly 1:1
to existing validations, and then used my judgement on some places that
felt distinct enough to warrant a separate error. Every error in the
compiler now has to supply both a severity (for legacy reasons) and a
category (for ESLint). Each category corresponds 1:1 to a ESLint rule
definition, so that the set of rules is automatically populated based on
the defined categories.

Categories include a flag for whether they should be in the recommended
set or not.

Note that as with the original version of this PR, only
eslint-plugin-react-compiler is changed. We still have to update the
main lint rule.

## Test Plan

* Created a sample project using ESLint v9 and verified that the plugin
can be configured correctly and detects errors
* Edited `fixtures/eslint-v9` and introduced errors, verified that the w
latest config changes in that fixture it correctly detects the errors
* In the sample project, confirmed that the LRU caching is correctly
caching compiler output, ie compiling files just once.

Co-authored-by: Mofei Zhang <feifei0@meta.com>

DiffTrain build for [7d29ecbeb2](https://github.com/facebook/react/commit/7d29ecbeb24327fdcd889fe184311bbeb0f04c30)
2025-08-21 15:03:15 -07:00
kassens a03985db6c Update Flow to 0.261 (#34255)
- 0.261 required to pull out a constant to preserve refinement
- 0.259 needed some updated suppressions for hacky stuff

DiffTrain build for [d73b6f1110](https://github.com/facebook/react/commit/d73b6f111057e09b9886e8edd2bc70fa56229489)
2025-08-21 12:12:59 -07:00
poteto 133db888c0 Add flow suppression for Constant Condition rollout (#34243)
DiffTrain build for [83c7379b96](https://github.com/facebook/react/commit/83c7379b9601f25463826449256f0cd3d283702d)
2025-08-20 15:31:40 -07:00
jackpope 34a9496a51 [eslint-plugin-react-hooks][RulesOfHooks] handle React.useEffect in addition to useEffect (#34076)
## Summary

This is a fix for https://github.com/facebook/react/issues/34074

## How did you test this change?

I added tests in the eslint package, and ran `yarn jest`. After adding
the new tests, I have this:

On main | On this branch
-|-
<img width="356" height="88" alt="image"
src="https://github.com/user-attachments/assets/4ae099a1-0156-4032-b2ca-635ebadcaa3f"
/> | <img width="435" height="120" alt="image"
src="https://github.com/user-attachments/assets/b06c04b8-6cec-43de-befa-a8b4dd20500e"
/>

## Changes

- Add tests to check that we are checking both `CallExpression`
(`useEffect(`), and `MemberExpression` (`React.useEffect(`). To do that,
I copied the `getNodeWithoutReactNamespace(` fn from `ExhaustiveDeps.ts`
to `RulesOfHooks.ts`

DiffTrain build for [87a45ae37f](https://github.com/facebook/react/commit/87a45ae37f4014b6df548a5d9b06bad5dc557992)
2025-08-18 06:21:23 -07:00
josephsavona dd5e4fd26c [compiler] Remove now-unused FunctionEffect type (#34029)
The new mutation/aliasing model significantly expands on the idea of
FunctionEffect. The type (and its usage in HIRFunction.effects) was only
necessary for the now-deleted old inference model so we can clean up
this code now.

DiffTrain build for [5063b3283f](https://github.com/facebook/react/commit/5063b3283fcae4bb43756d0d18d32008e3910bea)
2025-08-15 15:33:47 -07:00
josephsavona 2ea3843722 [compiler][wip] Remove old mutation/aliasing implementation (#34028)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34028).
* #34029
* __->__ #34028

DiffTrain build for [eaf6adb127](https://github.com/facebook/react/commit/eaf6adb1277e4cb4f91d1b7f687f773657a5751b)
2025-08-15 15:27:27 -07:00
josephsavona 87b4e0d792 [compiler] Add support for diagnostic hints (#34126)
Hints are meant as additional information to present to the developer
about an error. The first use-case here is for the suggestion to name
refs with "-Ref" if we encounter a mutation that looks like it might be
a ref. The original error printing used a second error detail which
printed the source code twice, a hint with just extra text is less
noisy.

DiffTrain build for [6ffcac8558](https://github.com/facebook/react/commit/6ffcac8558efbd204c7df5d52787a90e507dd8d7)
2025-08-15 15:16:08 -07:00
josephsavona 8ef2e214bb [compiler] Add hint to name variables with "Ref" suffix (#34125)
If you have a ref that the compiler doesn't know is a ref (say, a value
returned from a custom hook) and try to assign its `.current = ...`, we
currently fail with a generic error that hook return values are not
mutable. However, an assignment to `.current` specifically is a very
strong hint that the value is likely to be a ref. So in this PR, we
track the reason for the mutation and if it ends up being an error, we
use it to show an additional hint to the user. See the fixture for an
example of the message.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34125).
* #34126
* __->__ #34125
* #34124

DiffTrain build for [724b324b96](https://github.com/facebook/react/commit/724b324b966343f08ff0cb16ec9d8013e3891dfd)
2025-08-15 15:12:24 -07:00
jackpope 52f44c7f0f Add compareDocumentPosition to Fabric FragmentInstance (#34103)
Stacked on https://github.com/facebook/react/pull/34069

Same basic semantics as the react-dom for determining document position
of a Fragment compared to a given node. It's simpler here because we
don't have to deal with inserted nodes or portals. So we can skip a
bunch of the validation logic.

The logic for handling empty fragments is the same so I've split out
`compareDocumentPositionForEmptyFragment` into a shared module. There
doesn't seem to be a great place to put shared DOM logic between Fabric
and DOM configs at the moment. There may be more of this coming as we
add more and more DOM APIs to RN.

For testing I've written Fantom tests internally which pass the basic
cases on this build. The renderer we have configured for Fabric tests in
the repo doesn't support the Element APIs we need like
`compareDocumentPosition`.

DiffTrain build for [45a6532a08](https://github.com/facebook/react/commit/45a6532a088432010c40cbcac1fb6b6f8d56dd69)
2025-08-15 12:13:56 -07:00