7131 Commits

Author SHA1 Message Date
Ricky
074d96b9dd [flags] land enableTrustedTypesIntegration (#35816)
## Summary

This flag enables React's integration with the browser [Trusted Types
API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API).

The Trusted Types API is a browser security feature that helps prevent
DOM-based XSS attacks. When a site enables Trusted Types enforcement via
`Content-Security-Policy: require-trusted-types-for 'script'`, the
browser requires that values passed to DOM injection sinks (like
`innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`,
`TrustedScriptURL`) created through developer-defined sanitization
policies, rather than raw strings.

 ### What changed

Previously, React always coerced values to strings (via `'' + value`)
before passing them to DOM APIs like `setAttribute` and `innerHTML`.
This broke Trusted Types because it converted typed objects into plain
strings, which the browser would then reject under Trusted Types
enforcement.

React now passes values directly to DOM APIs without string coercion,
preserving Trusted Types objects so the browser can validate them. This
applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and
URL attributes (`href`, `action`, etc).

 ### Before (broken)

Using Trusted Types with something like`dangerouslySetInnerHTML` would
throw:

 ```js
 const sanitizer = trustedTypes.createPolicy('sanitizer', {
   createHTML: (input) => DOMPurify.sanitize(input),
 });

 function Comment({text}) {
   const clean = sanitizer.createHTML(text);
   // clean is a TrustedHTML object, but React would call '' + clean,
   // converting it back to a plain string before setting innerHTML.
   // Under Trusted Types enforcement, the browser rejects the string:
   //
   //   TypeError: Failed to set 'innerHTML' on 'Element':
   //   This document requires 'TrustedHTML' assignment.
   return <div dangerouslySetInnerHTML={{__html: clean}} />;
 }
 ```

### After (works)

React now passes the TrustedHTML object directly to the DOM without
stringifying it:

```js
 const policy = trustedTypes.createPolicy('sanitizer', {
   createHTML: (input) => DOMPurify.sanitize(input),
 });

 function Comment({text}) {
   // TrustedHTML objects are passed directly to innerHTML
   return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />;
 }

 function UserProfile({bio}) {
   // String attribute values also preserve Trusted Types objects
   return <div data-bio={policy.createHTML(bio)} />;
 }
 ```

 ## Non-breaking change

 - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified.
 - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
2026-02-25 14:49:30 -05:00
Mushaheed Kapadia
c0060cf2a6 [DevTools] Enable support for the React DevTools Client to connect to different host/port/path (#35886)
## Summary

This enables routing the React Dev Tools through a remote server by
being able to specify host, port, and path for the client to connect to.
Basically allowing the React Dev Tools server to have the client connect
elsewhere.

This setups a `clientOptions` which can be set up through environment
variables when starting the React Dev Tools server.

This change shouldn't affect the traditional usage for React Dev Tools.

EDIT: the additional change was moved to another PR 

## How did you test this change?

Run React DevTools with 
```
$ REACT_DEVTOOLS_CLIENT_HOST=<MY_HOST> REACT_DEVTOOLS_CLIENT_PORT=443 REACT_DEVTOOLS_CLIENT_USE_HTTPS=true REACT_DEVTOOLS_PATH=/__react_devtools__/ yarn start

```

Confirm that my application connects to the local React Dev Tools
server/instance/electron app through my remote server.
2026-02-24 15:36:32 +00:00
Mushaheed Kapadia
bd76b456c1 [DevTools] Fix ReactDevToolsBackend module for AMD (#35891)
## Summary

For apps that use AMD, we need to actually `require()` the
ReactDevToolsBackend and load it from the AMD module cache. This adds a
check for the case where the `ReactDevToolsBackend` isn't defined
globally, and so we load it with `require()`.


## How did you test this change?

Tested through https://github.com/facebook/react/pull/35886
2026-02-24 15:27:59 +00:00
Andrew Clark
ab18f33d46 Fix context propagation through suspended Suspense boundaries (#35839)
When a Suspense boundary suspends during initial mount, the primary
children's fibers are discarded because there is no current tree to
preserve them. If the suspended promise never resolves, the only way to
retry is something external like a context change. However, lazy context
propagation could not find the consumer fibers — they no longer exist in
the tree — so the Suspense boundary was never marked for retry and
remained stuck in fallback state indefinitely.

The fix teaches context propagation to conservatively mark suspended
Suspense boundaries for retry when a parent context changes, even when
the consumer fibers can't be found. This matches the existing
conservative approach used for dehydrated (SSR) Suspense boundaries.
2026-02-20 22:03:11 -05:00
Sebastian "Sebbie" Silbermann
2ba3065527 [Flight] Add support for transporting Error.cause (#35810) 2026-02-19 15:50:34 -08:00
Josh Story
38cd020c1f Don't outline Suspense boundaries with suspensey CSS during shell flush (#35824)
When flushing the shell, stylesheets with precedence are emitted in the
`<head>` which blocks paint regardless. Outlining a boundary solely
because it has suspensey CSS provides no benefit during the shell flush
and causes a higher-level fallback to be shown unnecessarily (e.g.
"Middle Fallback" instead of "Inner Fallback").

This change passes a flushingInShell flag to hasSuspenseyContent so the
host config can skip stylesheet-only suspensey content when flushing the
shell. Suspensey images (used for ViewTransition animation reveals)
still trigger outlining during the shell since their motivation is
different.

When flushing streamed completions the behavior is unchanged — suspensey
CSS still causes outlining so the parent content can display sooner
while the stylesheet loads.
2026-02-19 12:29:21 -08:00
Tim Neutkens
f247ebaf44 [Flight] Walk parsed JSON instead of using reviver for parsing RSC payload (#35776)
## Summary

Follow-up to https://github.com/vercel/next.js/pull/89823 with the
actual changes to React.

Replaces the `JSON.parse` reviver callback in `initializeModelChunk`
with a two-step approach: plain `JSON.parse()` followed by a recursive
`reviveModel()` post-process (same as in Flight Reply Server). This
yields a **~75% speedup** in RSC chunk deserialization.

| Payload | Original (ms) | Walk (ms) | Speedup |
|---------|---------------|-----------|---------|
| Small (2 elements, 142B) | 0.0024 | 0.0007 | **+72%** |
| Medium (~12 elements, 914B) | 0.0116 | 0.0031 | **+73%** |
| Large (~90 elements, 16.7KB) | 0.1836 | 0.0451 | **+75%** |
| XL (~200 elements, 25.7KB) | 0.3742 | 0.0913 | **+76%** |
| Table (1000 rows, 110KB) | 3.0862 | 0.6887 | **+78%** |

## Problem

`createFromJSONCallback` returns a reviver function passed as the second
argument to `JSON.parse()`. This reviver is called for **every key-value
pair** in the parsed JSON. While the logic inside the reviver is
lightweight, the dominant cost is the **C++ → JavaScript boundary
crossing** — V8's `JSON.parse` is implemented in C++, and calling back
into JavaScript for every node incurs significant overhead.

Even a trivial no-op reviver `(k, v) => v` makes `JSON.parse` **~4x
slower** than bare `JSON.parse` without a reviver:

```
108 KB payload:
  Bare JSON.parse:    0.60 ms
  Trivial reviver:    2.95 ms  (+391%)
```

## Change

Replace the reviver with a two-step process:

1. `JSON.parse(resolvedModel)` — parse the entire payload in C++ with no
callbacks
2. `reviveModel` — recursively walk the resulting object in pure
JavaScript to apply RSC transformations

The `reviveModel` function includes additional optimizations over the
original reviver:
- **Short-circuits plain strings**: only calls `parseModelString` when
the string starts with `$`, skipping the vast majority of strings (class
names, text content, etc.)
- **Stays entirely in JavaScript** — no C++ boundary crossings during
the walk

## Results

You can find the related applications in the [Next.js PR
](https://github.com/vercel/next.js/pull/89823)as I've been testing this
on Next.js applications.

### Table as Server Component with 1000 items

Before:

```
    "min": 13.782875000000786,
    "max": 22.23400000000038,
    "avg": 17.116868530000083,
    "p50": 17.10766700000022,
    "p75": 18.50787499999933,
    "p95": 20.426249999998618,
    "p99": 21.814125000000786
```

After:

```
    "min": 10.963916999999128,
    "max": 18.096083000000363,
    "avg": 13.543286884999988,
    "p50": 13.58350000000064,
    "p75": 14.871791999999914,
    "p95": 16.08429099999921,
    "p99": 17.591458000000785
```

### Table as Client Component with 1000 items

Before:

```
    "min": 3.888875000000553,
    "max": 9.044959000000745,
    "avg": 4.651271475000067,
    "p50": 4.555749999999534,
    "p75": 4.966624999999112,
    "p95": 5.47754200000054,
    "p99": 6.109499999998661
````

After:

```
    "min": 3.5986250000005384,
    "max": 5.374291000000085,
    "avg": 4.142990245000046,
    "p50": 4.10570799999914,
    "p75": 4.392041999999492,
    "p95": 4.740084000000934,
    "p99": 5.1652500000000146
```

### Nested Suspense

Before:

```
  Requests:  200
  Min:       73ms
  Max:       106ms
  Avg:       78ms
  P50:       77ms
  P75:       80ms
  P95:       85ms
  P99:       94ms
```

After:

```
  Requests:  200
  Min:       56ms
  Max:       67ms
  Avg:       59ms
  P50:       58ms
  P75:       60ms
  P95:       65ms
  P99:       66ms
```

### Even more nested Suspense (double-level Suspense)

Before:

```
  Requests:  200
  Min:       159ms
  Max:       208ms
  Avg:       169ms
  P50:       167ms
  P75:       173ms
  P95:       183ms
  P99:       188ms
```

After:

```
  Requests:  200
  Min:       125ms
  Max:       170ms
  Avg:       134ms
  P50:       132ms
  P75:       138ms
  P95:       148ms
  P99:       160ms
```

## How did you test this change?

Ran it across many Next.js benchmark applications.

The entire Next.js test suite passes with this change.

---------

Co-authored-by: Hendrik Liebau <mail@hendrik-liebau.de>
2026-02-19 08:37:41 -08:00
Sebastian "Sebbie" Silbermann
3a2bee26d2 [DevTools] Fix alignment of breadcrumbs separator (#35817) 2026-02-18 10:53:49 -08:00
chirokas
4842fbea02 [react-dom] Add support for onFullscreenChange and onFullscreenError events (#34621) 2026-02-17 17:34:16 -08:00
Nick Gerleman
61db53c179 [Native] Add RCTSelectableText as a recognized Text component (#35780)
## Summary

Add "RCTSelectableText" to the list of component names recognized as
being inside a text element, alongside "RCTText".

React Native's new text stack, tries to optimize and allows
differentiating between a custom TextView, with lower level control,
that can reuse the work performed during Fabric/Yoga layout, and a
native TextView, used for fidelity. On Android at least, the only place
we've needed native TextView for fidelity/native UX has been support for
`selectable` text, which has many unique UI interactions.

## How did you test this change?

When I patch this in, alongside
https://github.com/facebook/react-native/pull/55552, we no longer see
warnings when we render text inside of RCTSelectableText component.

---------

Co-authored-by: Eli White <github@eli-white.com>
2026-02-17 16:16:06 -08:00
Hendrik Liebau
47d1ad1454 [Flight] Skip transferReferencedDebugInfo during debug info resolution (#35795)
When the Flight Client resolves chunk references during model parsing,
it calls `transferReferencedDebugInfo` to propagate debug info entries
from referenced chunks to the parent chunk. Debug info on chunks is
later moved to their resolved values, where it is used by React DevTools
to show performance tracks and what a component was suspended by.

Debug chunks themselves (specifically `ReactComponentInfo`,
`ReactAsyncInfo`, `ReactIOInfo`, and their outlined references) are
metadata that is never rendered. They don't need debug info attached to
them. Without this fix, debug info entries accumulate on outlined debug
chunks via their references to other debug chunks (e.g. owner chains and
props deduplication paths). Since each outlined chunk's accumulated
entries are copied to every chunk that references it, this creates
exponential growth in deep component trees, which can cause the dev
server to hang and run out of memory.

This generalizes the existing skip of `transferReferencedDebugInfo` for
Element owner/stack references (which already recognizes that references
to debug chunks don't need debug info transferred) to all references
resolved during debug info resolution. It adds an
`isInitializingDebugInfo` flag set in `initializeDebugChunk` and
`resolveIOInfo`, which propagates through all nested
`initializeModelChunk` calls within the same synchronous stack. For the
async path, `waitForReference` captures the flag at call time into
`InitializationReference.isDebug`, so deferred fulfillments also skip
the transfer.
2026-02-16 09:22:32 -08:00
Azat S.
e8c6362678 [eslint-plugin-react-hooks] Add ESLint v10 support (#35720)
## Summary

ESLint v10.0.0 was released on February 7, 2026. The current
`peerDependencies` for `eslint-plugin-react-hooks` only allows up to
`^9.0.0`, which causes peer dependency warnings when installing with
ESLint v10.

This PR:

- Adds `^10.0.0` to the eslint peer dependency range
- Adds `eslint-v10` to devDependencies for testing
- Adds an `eslint-v10` e2e fixture (based on the existing `eslint-v9`
fixture)

ESLint v10's main breaking changes (removal of legacy eslintrc config,
deprecated context methods) don't affect this plugin - flat config is
already supported since v7.0.0, and the deprecated APIs already have
fallbacks in place.

## How did you test this change?

Ran the existing unit test suite:

```
cd packages/eslint-plugin-react-hooks && yarn test
```

All 5082 tests passed.
2026-02-13 10:26:01 -08:00
Ruslan Lesiutin
03ca38e6e7 [DevTools] Check suspense child node presence in parentSuspense.children before removing (#35775)
Currently, this silently removes the last child in the list, which
doesn't contain the `id`.
2026-02-13 15:33:22 +00:00
Sebastian "Sebbie" Silbermann
6066c782fe [DevTools] Dedicated empty state for roots that aren't suspended by anything (#35769) 2026-02-12 17:48:02 +01:00
Sebastian "Sebbie" Silbermann
705055d7ac [DevTools] Enable Suspense tab by default (#35768) 2026-02-12 16:50:29 +01:00
Ruslan Lesiutin
8374c2abf1 [DevTools] Remove experimental __IS_INTERNAL_MCP_BUILD__ flag and related code (#35755)
This is unused.
2026-02-11 16:59:43 +00:00
Ricky
892c68605c [fiber] bugfix - don't show <Offscreen> in error message. (#35763)
## Overview

While building the RSC sandboxes I notice error messages like:

>  An error occurred in the `<Offscreen>` component

This is an internal component so it should show either:

>  An error occurred in the `<Suspense>` component.

>  An error occurred in the `<Activity>` component.

It should only happen when there's a lazy in the direct child position
of a `<Suspense>` or `<Activity>` component.
2026-02-11 11:20:51 -05:00
Jack Pope
cd515d7e22 Minor DOM FragmentInstance refactors (#35641)
Handles TODOs, small follow up refactors
2026-02-11 10:03:36 -05:00
Jack Pope
78f5c504b7 Notify FragmentInstance of added/removed text (#35637)
Follow up to https://github.com/facebook/react/pull/35630

We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.

Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
2026-02-11 09:26:22 -05:00
Sebastian "Sebbie" Silbermann
e49335e961 [DevTools] Display React.optimisticKey in key positions (#35760) 2026-02-11 00:35:36 +01:00
Sebastian "Sebbie" Silbermann
57b79b0388 [DevTools] Only block child Suspense boundaries if the parent has all shared suspenders removed (#35737) 2026-02-10 17:52:35 +01:00
Sebastian "Sebbie" Silbermann
70890e7c58 Consistent handling of work tags for rename, delete, and overriding state (#35740)
Co-authored-by: Ruslan Lesiutin <28902667+hoxyq@users.noreply.github.com>
2026-02-10 16:35:02 +01:00
Sebastian "Sebbie" Silbermann
f23aa1d9f5 [DevTools] Fix memory leak when unmounting hoistables (#35741) 2026-02-10 13:09:23 +01:00
Sebastian "Sebbie" Silbermann
49c3b270f9 [test] Include uniqueSuspenders in Suspense tree snapshots (#35736) 2026-02-10 12:51:58 +01:00
Ruslan Lesiutin
c6bb26bf83 [DevTools] Don't capture durations for disconnected subtrees when profiling (#35718)
After https://github.com/facebook/react/pull/34089, when updating
(possibly, mounting) inside disconnected subtree, we don't record this
as an operation. This only happens during reconnect. The issue is that
`recordProfilingDurations()` can be called, which diffs tree base
duration and reports it to the Frontend:

65db1000b9/packages/react-devtools-shared/src/backend/fiber/renderer.js (L4506-L4521)

This operation can be recorded before the "Add" operation, and it will
not be resolved properly on the Frontend side.

Before the fix:
```
commit tree › Suspense › should handle transitioning from fallback back to content during profiling

    Could not clone the node: commit tree does not contain fiber "5". This is a bug in React DevTools.

      162 |     const existingNode = nodes.get(id);
      163 |     if (existingNode == null) {
    > 164 |       throw new Error(
          |             ^
      165 |         `Could not clone the node: commit tree does not contain fiber "${id}". This is a bug in React DevTools.`,
      166 |       );
      167 |     }

      at getClonedNode (packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:164:13)
      at updateTree (packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:348:24)
      at getCommitTree (packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:112:20)
      at ProfilingCache.getCommitTree (packages/react-devtools-shared/src/devtools/ProfilingCache.js:40:46)
      at Object.<anonymous> (packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js:257:44)
```
2026-02-09 22:18:17 +00:00
Sebastian "Sebbie" Silbermann
6a939d0b54 [DevTools] Allow renaming Host Component props (#35735) 2026-02-09 23:14:46 +01:00
Sebastian "Sebbie" Silbermann
4c9d62d2b4 [DevTools] Fix crash when revealing stable, filtered <Activity> children (#35734) 2026-02-09 22:52:24 +01:00
Ruslan Lesiutin
24f215ce8b [DevTools] Fix false-positive re-render reports for filtered nodes (#35723)
Fixes https://github.com/facebook/react/issues/33423,
https://github.com/facebook/react/issues/35245,
https://github.com/facebook/react/issues/19732.

As demoed
[here](https://github.com/facebook/react/issues/33423#issuecomment-2970750588),
React DevTools incorrectly highlights re-renders for descendants of
filtered-out nodes that didn't actually render.

There were multiple fixes suggesting changes in `didFiberRender()`
function, but these doesn't seem right, because this function is used in
a context of whether the Fiber actually rendered something (updated),
not re-rendered compared to the previous Fiber.

Instead, this PR adds additional validation at callsites that either
used for highlighting re-renders or capturing tree base durations and
are relying on `didFiberRender`. I've also added a few tests that
reproduce the failure scenario. Without the changes, the tests are
failing.
2026-02-09 20:39:33 +00:00
Sebastian "Sebbie" Silbermann
eab523e2a9 [Fiber] Avoid duplicate debug info for array children (#35733) 2026-02-09 20:36:56 +01:00
Hendrik Liebau
272441a9ad [Flight] Add unstable_allowPartialStream option to Flight Client (#35731)
When using a partial prerender stream, i.e. a prerender that is
intentionally aborted before all I/O has resolved, consumers of
`createFromReadableStream` would need to keep the stream unclosed to
prevent React Flight from erroring on unresolved chunks. However, some
browsers (e.g. Chrome, Firefox) keep unclosed ReadableStreams with
pending reads as native GC roots, retaining the entire Flight response.

With this PR we're adding an `unstable_allowPartialStream` option, that
allows consumers to close the stream normally. The Flight Client's
`close()` function then transitions pending chunks to halted instead of
erroring them. Halted chunks keep Suspense fallbacks showing (i.e. they
never resolve), and their `.then()` is a no-op so no new listeners
accumulate. Inner stream chunks (ReadableStream/AsyncIterable) are
closed gracefully, and `getChunk()` returns halted chunks for new IDs
that are accessed after closing the response. Blocked chunks are left
alone because they may be waiting on client-side async operations like
module loading, or on forward references to chunks that appeared later
in the stream, both of which resolve independently of closing.
2026-02-09 19:19:32 +01:00
Hendrik Liebau
b07aa7d643 [Flight] Fix encodeReply for JSX with temporary references (#35730)
`encodeReply` throws "React Element cannot be passed to Server Functions
from the Client without a temporary reference set" when a React element
is the root value of a `serializeModel` call (either passed directly or
resolved from a promise), even when a temporary reference set is
provided.

The cause is that `resolveToJSON` hits the `REACT_ELEMENT_TYPE` switch
case before reaching the `existingReference`/`modelRoot` check that
regular objects benefit from. The synthetic JSON root created by
`JSON.stringify` is never tracked in `writtenObjects`, so
`parentReference` is `undefined` and the code falls through to the
throw. This adds a `modelRoot` check in the `REACT_ELEMENT_TYPE` case,
following the same pattern used for promises and plain objects.

The added `JSX as root model` test also uncovered a pre-existing crash
in the Flight Client: when the JSX element round-trips back, it arrives
as a frozen object (client-created elements are frozen in DEV), and
`Object.defineProperty` for `_debugInfo` fails because frozen objects
are non-configurable. The same crash can occur with JSX exported as a
client reference. For now, we're adding `!Object.isFrozen()` guards in
`moveDebugInfoFromChunkToInnerValue` and `addAsyncInfo` to prevent the
crash, which means debug info is silently dropped for frozen elements.
The proper fix would likely be to clone the element so each rendering
context gets its own mutable copy with correct debug info.

closes #34984
closes #35690
2026-02-09 16:17:53 +01:00
Jimmy Lai
2dd9b7cf76 [Flight] Fix debug channel flag in Node.js server renderToPipeableStream (#35724)
## Summary

- Fixes the `createRequest` call in `renderToPipeableStream` to pass
`debugChannelReadable !== undefined` instead of `debugChannel !==
undefined` in the turbopack, esm, and parcel Node.js server
implementations
- The webpack version already had the correct check; this brings the
other bundler implementations in line

The bug was introduced in #33754. With `debugChannel !== undefined`, the
server could signal that debug info should be emitted even when only a
write-only debug channel is provided (no readable side), potentially
causing the client to block forever waiting for debug data that never
arrives.
2026-02-08 20:14:15 +01:00
Sebastian "Sebbie" Silbermann
65db1000b9 [test] Move profilingCommitTreeBuilder to versioned renderer (#35711) 2026-02-06 16:00:43 +01:00
Sebastian "Sebbie" Silbermann
2a879cdc95 [DevTools] Fix broken commit tree builder for initial operations (#35710) 2026-02-06 15:16:23 +01:00
Sebastian "Sebbie" Silbermann
9a5996a6c1 [flags] Cleanup enableHalt (#35708) 2026-02-06 10:33:51 +01:00
Sebastian "Sebbie" Silbermann
1c66ac740c [DevTools] Separate breadcrumbs with » (#35705) 2026-02-06 00:40:31 +01:00
Sebastian "Sebbie" Silbermann
8b276df415 [DevTools] Avoid scrollbars in Suspense breadcrumbs (#35700) 2026-02-05 23:27:57 +01:00
Ricky
95ffd6cd9c Disable parallel transitions in canary (#35709)
Accidentally enabled this
2026-02-05 13:34:23 -05:00
Ruslan Lesiutin
b9323509be [DevTools] Throw an error when attempting to clone non-existent node (#35702)
There is an existing issue with serialisation logic for the traces from
Profiler panel.

I've discovered that `TREE_OPERATION_UPDATE_TREE_BASE_DURATION`
operation for some reason appears earlier in a sequence of operations,
before the `TREE_OPERATION_ADD` that registers the new node. It ends up
cloning non-existent node, which just creates an empty object and adds
it to the map of nodes.

This change only adds additional layer of validation to cloning logic,
so we don't swallow the error, if we attempt to clone non-existent node.
2026-02-05 17:49:18 +00:00
Sebastian "Sebbie" Silbermann
bb53387716 [DevTools] Shrink/Deshrink Owners breadcrumbs on any resizes (#35694) 2026-02-05 12:08:02 +01:00
Ricky
3aaab92a26 [flags] add enableEffectEventMutationPhase (#35548)
Small optimization for useEffectEvent. Not sure we even need a flag for
it, but it will be a nice killswitch.

As an added benefit, it fixes a bug when `enableViewTransition` is on,
where we were not updating the useEffectEvent callback when a tree went
from hidden to visible.
2026-02-04 15:04:57 -05:00
Ricky
087a34696f [test] add activity test with gSBU and enableViewTransition bugfix (#35555)
Related to https://github.com/facebook/react/pull/35548,
`enableViewTransition` fixes a bug where `getSnapshotBeforeUpdate` was
running in hidden trees when it shouldn't (`componentWillUpdate` won't
run for hidden updates, and when it becomes visible it will be called
with `componentWillMount`).
2026-02-04 14:37:45 -05:00
Ricky
6913ea4d28 [flags] Add enableParallelTransitions (#35392)
## Overview

Adds a feature flag `enableParallelTransitions` to experiment with
engantling transitions less often.

## Motivation

Currently we over-entangle transition lanes. 

It's a common misunderstanding that React entangles all transitions,
always. We actually will complete transitions independently in many
cases. For example, [this
codepen](https://codepen.io/GabbeV/pen/pvyKBrM) from
[@gabbev](https://bsky.app/profile/gabbev.bsky.social/post/3m6uq2abihk2x)
shows transitions completing independently.

However, in many cases we entangle when we don't need to, instead of
letting the independent transitons complete independently. We still want
to entangle for updates that happen on the same queue.

## Example

As an example of what this flag would change, consider two independent
counter components:

```js
function Counter({ label }) {
  const [count, setCount] = useState(0);

  return (
    <div>
      <span>{use(readCache(`${label} ${count}`))} </span>
      <Button
        action={() => {
          setCount((c) => c + 1);
        }}
      >
        Next {label}
      </Button>
    </div>
  );
}
```
```js
export default function App() {
  return (
    <>
      <Counter label="A" />
      <Counter label="B" />
    </>
  );
}
```

### Before
The behavior today is to entange them, meaning they always commit
together:



https://github.com/user-attachments/assets/adead60e-8a98-4a20-a440-1efdf85b2142

### After

In this experiment, they will complete independently (if they don't
depend on each other):


https://github.com/user-attachments/assets/181632b5-3c92-4a29-a571-3637f3fab8cd

## Early Research

This change is in early research, and is not in the experimental
channel. We're going to experiment with this at Meta to understand how
much of a breaking change, and how beneficial it is before commiting to
shipping it in experimental and beyond.
2026-02-04 13:58:34 -05:00
Hendrik Liebau
cf993fb457 [Flight] Fix stack overflow in visitAsyncNode with deep async chains (#35612)
Database libraries like Gel/EdgeDB can create very long linear chains of
async sequences through temporal async sequencing in connection pools.
The recursive traversal of `node.previous` chains in `visitAsyncNode`
causes stack overflow on these deep chains.

The fix converts the `previous` chain traversal from recursive to
iterative. We collect the chain into an array, then process from deepest
to shallowest.

The `awaited` traversal remains recursive since its depth is bounded by
promise dependency depth, not by the number of event loop turns. Each
`awaited` branch still benefits from the iterative `previous` handling
within its own traversal.

I've verified that this fixes the
[repro](https://github.com/jere-co/next-debug) provided in #35246.

closes #35246
2026-02-04 19:43:23 +01:00
Jorge Cabiedes
c137dd6f54 Fix exhaustive deps bug with flow type casting. (#35691)
Summary:
I noticed there's a bug where the lint will recognize the type on a cast
annotation as a missing dependency;

```
        function MyComponent() {
          type ColumnKey = 'id' | 'name';
          type Item = {id: string, name: string};

          const columns = useMemo(
            () => [
              {
                type: 'text',
                key: 'id',
              } as TextColumn<ColumnKey, Item>,
                              ^^^^^^^^ here
            ],
            [],
          );
        }
```

This is due to the AST of AsExpressions being something like:

AsExpression
  └── typeAnnotation: GenericTypeAnnotation
        └── typeParameters: TypeParameterInstantiation
              └── params[0]: GenericTypeAnnotation
                    └── id: Identifier (name: "ColumnKey")

Where `ColumnKey` never has a TypeParameter Annotation. So we need to
consider it to be a flow type due to it belonging to a
GenericTypeAnnotation

Test Plan:
Added unit tests

Before:
```
Test Suites: 1 failed, 2 passed, 3 total
Tests:       2 failed, 5065 passed, 5067 total
Snapshots:   0 total
Time:        16.517 s
Ran all test suites.
error Command failed with exit code 1.
```

After:
```
 PASS  __tests__/ReactCompilerRuleTypescript-test.ts
 PASS  __tests__/ESLintRulesOfHooks-test.js (6.192 s)
 PASS  __tests__/ESLintRuleExhaustiveDeps-test.js (9.97 s)

Test Suites: 3 passed, 3 total
Tests:       5067 passed, 5067 total
Snapshots:   0 total
Time:        10.21 s, estimated 11 s
Ran all test suites.
  Done in 12.66s.
```
2026-02-04 08:24:24 -08:00
Sebastian "Sebbie" Silbermann
f84ce5a45c [flags] Turn on enableViewTransition in OSS react-test-renderer (#35684) 2026-02-04 11:42:49 +01:00
Sebastian "Sebbie" Silbermann
c9ff56ec74 [DevTools] Disable Activity slices by default (#35685) 2026-02-04 10:56:33 +01:00
Sebastian "Sebbie" Silbermann
6853d7ab2f [Perf Tracks] Prevent crash when accessing $$typeof (#35679) 2026-02-03 17:53:45 +01:00
Sebastian "Sebbie" Silbermann
e32c126121 [flags] Turn on enableAsyncDebugInfo everywhere (#35683) 2026-02-03 17:52:57 +01:00
Ricky
3e00319b35 [Flight] allow context providers from client modules (#35675)
Allows Server Components to import Context from a `"use client'` module
and render its Provider.

Only tricky part was that I needed to add `REACT_CONTEXT_TYPE` handling
in mountLazyComponent so lazy-resolved Context types can be rendered.
Previously only functions, REACT_FORWARD_REF_TYPE, and REACT_MEMO_TYPE
were handled.

Tested in the Flight fixture.

ty bb claude

Closes https://github.com/facebook/react/issues/35340

---------

Co-authored-by: Sophie Alpert <git@sophiebits.com>
2026-02-03 10:22:57 -05:00