Skip to content

Pick feature flag to enable experimental MutationObserver (#55919)#56599

Closed
rubennorte wants to merge 45 commits into
react:mainfrom
rubennorte:pick-mutationobserver-featureflag-85
Closed

Pick feature flag to enable experimental MutationObserver (#55919)#56599
rubennorte wants to merge 45 commits into
react:mainfrom
rubennorte:pick-mutationobserver-featureflag-85

Conversation

@rubennorte

Copy link
Copy Markdown
Contributor

Changelog: [internal]

Summary:

This picks #55919 into 0.85-stable, as we'll be testing this feature in apps using 0.85.

Changelog:

Not needed. It's gated behind a feature flag that's disabled by default.

Test Plan:

Tested e2e on Android and iOS using RN Tester. Everything compiles correctly.

alanleedev and others added 30 commits March 2, 2026 09:40
The build_android workflow was incorrectly using for dry-run
builds on stable branches (e.g., 0.85-stable), causing it to append  suffix
to the Hermes version. This resulted in trying to fetch non-existent SNAPSHOT artifacts
like in https://github.com/facebook/react-native/actions/runs/22592250332/job/65471130298.
This fix adds a check to detect stable branches (via github.ref_name or github.base_ref)
and uses  instead, which fetches the stable Hermes release from
Maven Central without the -SNAPSHOT suffix.

We check both github.ref_name and github.base_ref to cover two scenarios:
ref_name: Direct pushes to stable branches (e.g. pushing to 0.85-stable)
base_ref: Pull requests targeting stable branches (e.g. cherry-pick PRs where the source branch isn't named -stable but the target isChangelog: [Internal]
#publish-packages-to-npm&next
Summary:
Pull Request resolved: react#55925

Accidentally clobbered in D93247603. This affects the `fuseboxAssertSingleHostState` feature (react/react-native-devtools-frontend#218).

Changelog: [Internal]

Reviewed By: vzaidman

Differential Revision: D95365621

fbshipit-source-id: 0df7f7bb33bb6bf6eabe15c8ee06c1761567c84b
Summary:
Pull Request resolved: react#55613

The cloneMultiple method was written in a way to accept a list of families that are presumed to be owned by the api caller. This designe was mostly aimed at reanimated, that holds refernces to ShadowNodes (that own these families). In the case of AnimationBackend this didn't work properly, as when the view is unmounted we would lose the ShadowNodeFamily shared_ptr that we hold and it could get deallocated.

Since now we can get an owning reference to ShadowNodeFamily from ShadowNode::getFamilyShared, we don't have to keep this old unsafe api. Instead we require the caller to have an owning reference with the api itself.

This `cloneMultiple` method isn't really adopted in the community, so the breaking change shouldn't be a big problem.

Changelog:
[General][Breaking] - fix unsafe rawPointer access in cloneMultiple.

Reviewed By: zeyap, javache

Differential Revision: D93596770

fbshipit-source-id: c4d99b51875968ebce50358c19502cba02c50685
Summary:
Pull Request resolved: react#55729

This is added so that one can easily enables c++ AnimatedModule in open source.

If an app doesn't use `RCTAnimatedModuleProvider`(ios) or `AnimatedCxxReactPackage`(android), it can fallback to this default AnimatedModule when it has both c++animated and shared backend enabled
- shared backend removes the need to pass down start/stop callbacks to NativeAnimatedNodesManagerProvider, so we can cleanly initialize it as static default
  -  RCTAnimatedModuleProvider uses the version of AnimatedModule that still relies on a dedicated CADisplayLink for start/stop
  - AnimatedCxxReactPackage also bundles internal ViewEventModule (for NativeViewEvents) that shares `NativeAnimatedNodesManagerProvider` with AnimatedModule, but NativeViewEvents is not needed for open source
    - Alternatively we could also expose `NativeAnimatedNodesManagerProvider` via UIManager so other turbomodules can also use it. However I don't think it makes sense to double down on another animation API on UIManager given we have shared backend.
- This assumes DefaultTurboModules is always the fallback module provider. So it'll not override when app already uses RCTAnimatedModuleProvider or AnimatedCxxReactPackage

[General] [Added] - Add c++ AnimatedModule to DefaultTurboModules

Reviewed By: NickGerleman

Differential Revision: D94244698

fbshipit-source-id: 09e905eb4bad7d03cdf87d5b47352060b0e6212f
#publish-packages-to-npm&next
…t#56005)

Summary:
Pull Request resolved: react#56005

Changelog: [Internal]

The build_debugger_shell CI job was failing because build-binary.js
expects pkg.main to start with ./dist/, but without --prepack the
prepack.js script never runs, so main stays as ./src/index.js.

This was caused by a series of PRs:
- PR react#54857 refactored debugger-shell/package.json to use the
  publishConfig pattern, moving main from ./dist/index.js to
  ./src/index.js.
- PR react#55415 added the --prepack flag to build.js to support this.
- PR react#55416 added the build_debugger_shell CI job but ran yarn build
  without --prepack.

The fix passes --prepack to yarn build so that prepack.js rewrites
package.json main to ./dist/index.js before build-binary.js runs.

Reviewed By: huntie

Differential Revision: D95818417

fbshipit-source-id: 03c8340c415960c3937b13bdea3952798d2d420e
Summary:
Pull Request resolved: react#56100

## Changelog:

[iOS] [Fixed] - Revert RCTAnimatedModuleProvider change from D94244698

D94244698 added a guard in RCTAnimatedModuleProvider that returns nullptr
when useSharedAnimatedBackend() is true, expecting DefaultTurboModules to
handle AnimatedModule creation instead.

However, on iOS the TurboModule resolution chain in RCTReactNativeFactory
delegates to the app-provided getTurboModule:jsInvoker: and returns whatever
the delegate returns — even nullptr — without falling through to
DefaultTurboModules.

This causes `Invariant Violation: Native animated module is not available`
on any surface using Animated.View (e.g. Marketplace PDP) when
react_fabric.enable_shared_animated_backend_ios is enabled.

Revert the RCTAnimatedModuleProvider change from D94244698 so it always
provides AnimatedModule when cxxNativeAnimatedEnabled is true, regardless
of useSharedAnimatedBackend. The shared backend path in DefaultTurboModules
still exists as fallback for non-iOS platforms.

Reviewed By: christophpurrer

Differential Revision: D96611917

fbshipit-source-id: e01cf5c80dc4cbf30afac6bcf414616c15bfaddb
#publish-packages-to-npm&next
#publish-packages-to-npm&next
#publish-packages-to-npm&next
#publish-packages-to-npm&next
Summary:
When building React.XCFramework we build and link all source files in the XCFramework directly. To avoid Cocoapods to include the same files, we use a Ruby utility function called `podspec_sources` that will emit onlh header files when using (consuming) the build React.XFramework.

When running RN-Tester after building it using the following pod install command line we have effectively linked with the prebuilt XCFrameworks instead of building from source:

`# RCT_USE_RN_DEP=1  RCT_USE_PREBUILT_RNCORE=1 RCT_DEPS_VERSION=nightly RCT_TESTONLY_RNCORE_VERSION=nightly  bundle exec pod install`

The log in XCode will show an issue with duplciate symbols:

```
oobjc[2551]: Class _TtC10RCTSwiftUI23RCTSwiftUIContainerView is implemented in both xxxx/Library/Develope
r/CoreSimulator/Devices/72157AA1-8D26-424E-8C2E-62D701E70B4A/data/Containers/Bundle/Application/3C711879-443E-48F1-B422-740E7AE82A74/RNTester.app/Frameworks/React.framework/React (0x108d3fb90) and
xxx/Library/Developer/CoreSimulator/Devices/72157AA1-8D26-424E-8C2E-62D701E70B4A/data/Containers/Bundle/Application/3C711879-443E-48F1-B422-740E7AE82A74/RNTester.app/RNTester.debug.dylib
(0x1039ef780). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[2551]: Class _TtC10RCTSwiftUI18ContainerViewModel is implemented in both xxx/Library/Developer/CoreSimulator/Devices/72157AA1-8D26-424E-8C2E-62D701E70B4A/data/Containers/Bundle/Applicatio
n/3C711879-443E-48F1-B422-740E7AE82A74/RNTester.app/Frameworks/React.framework/React (0x108d43b98) and
xxx/Library/Developer/CoreSimulator/Devices/72157AA1-8D26-424E-8C2E-62D701E70B4A/data/Containers/Bundle/Application/3C711879-443E-48F1-B422-740E7AE82A74/RNTester.app/RNTester.debug.dylib
(0x1039f0288). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
```

This is because the RCTSwiftUI.podspec is missing using the `podspec_sources` function when setting up its source files:

```
s.source_files = "*.{h,m,swift}"
```

This will cause Xcode to both link with the XCFramework and compile the sources for this podspec once more - causing an app with duplicate symbols.

After applying this fix, the same test as above shows no duplicate symbols.

## Changelog:

[IOS] [FIXED] - Fixed duplicate symbol error when using React.XCFramework

Pull Request resolved: react#56139

Test Plan:
Run RN-Tester using the following pod install command line, causing us to link with the prebuilt XCFrameworks instead of building from source:

`# RCT_USE_RN_DEP=1  RCT_USE_PREBUILT_RNCORE=1 RCT_DEPS_VERSION=nightly RCT_TESTONLY_RNCORE_VERSION=nightly  bundle exec pod install`

Build/run the app, observe that the duplicate symbol message is gone.

Reviewed By: alanleedev

Differential Revision: D97317019

Pulled By: cipolleschi

fbshipit-source-id: 032113ad00890f712a6c70c3bd903f545f75aba1
Summary:
Follow-up to
- react#47033
- react#50431

TODO
- [x] bump packages/react-native/third-party-podspecs/fmt.podspec
- [x] bump scripts/releases/ios-prebuild/configuration.js
- [x] packages/react-native/third-party-podspecs/RCT-Folly.podspec
- [x] packages/react-native/gradle/libs.versions.toml
- [x] packages/rn-tester/Podfile.lock
  - rn-rester (main) ios not building on Xcode 26.3, CI currently only supports Xcode 16
  - i cannot downgrade macos26.4b4 locally to macos15 to install Xcode16.4 and bump pods this way
  - so on Xcode 26.3 i've attempted to bump only fmt minimally, ignoring remaining RN 0.86 hashes

Ref: https://github.com/search?q=repo%3Afacebook%2Freact-native+%2211.0.2%22&type=code

however unable to test rn-tester, ios doesn't seem to build on Xcode 26.3 let alone 26.4b
not tested previous versions of Xcode
not tested prior branches/tags to main

rn-tester CI is passing on old macos-15 Xcode 16.4.0 only, ideally this should be extended to stable macos lts and Xcode 26.3 stable first

separate follow-ups to this minimal fmt bump
- bump CI macos-15 xcode 16.1-4 to macos-26 xcode 26.0-3
- bump rn-tester Podfile.lock from RN 0.82 to 0.86 main (aka nightly)
- bump folly to 2025.11.03.00
- bump folly to 2026.03.09.00

Resolve: react#55601

[General][Changed] Bump fmt to 12.1.0 to fix Xcode 26.4

Pull Request resolved: react#56099

Test Plan: RNTester

Reviewed By: alanleedev

Differential Revision: D97358194

Pulled By: cipolleschi

fbshipit-source-id: 3eb578a99a310e3eb77433692bf35502d0d78d24
#publish-packages-to-npm&next
…eact#56265)

Summary:
Pull Request resolved: react#56265

When an async void TurboModule method throws an NSException,
performVoidMethodInvocation calls convertNSExceptionToJSError which
accesses the Hermes JSI runtime from the native method call invoker
thread. Since jsi::Runtime is not thread-safe, this causes heap
corruption and EXC_BAD_ACCESS crashes across various hermes::vm::*
functions.

The sibling function performMethodInvocation was already fixed in
D71619229 to re-throw the ObjC exception instead of converting to
JSError when the call is async. This applies the same fix to
performVoidMethodInvocation, which is always async.

Related to SEV S641230 (4,550+ Hermes crashes in AMA iOS from OTA
bundle 921191722). A JS change behind a QE/MC gate is triggering an
NSException in a void TurboModule method for non-employee users, and
this bug turns that into widespread memory corruption. This fix
prevents the crash, but the triggering diff and throwing TurboModule
still need to be identified separately.

Matches upstream GitHub issue: https://github.com/facebook/hermes/issues/1957Commits affecting the React Native open source repository must have a changelog
entry in the commit summary. Every React Native release has almost 1000 commits,
and manually categorizing these commits is very time consuming.

 ---

Changelog:
[iOS][Fixed] - Fix Hermes crash when async void TurboModule method throws NSException by re-throwing instead of converting to JSError on wrong thread

Reviewed By: javache

Differential Revision: D98660782

fbshipit-source-id: bdedc769f17d9aec4156c45d0286c6c31ca006e4
…ct#56151)

Summary:
When building React Native (`0.85.0-rc.5`) core from source (`RCT_USE_PREBUILT_RNCORE=0`), the `React-Fabric/animated` CocoaPods subspec flattens the `event_drivers/` subdirectory headers because `header_mappings_dir` is not set.

CocoaPods' `header_dir` without `header_mappings_dir` places all matched headers directly under the specified directory, losing any subdirectory structure. This means `event_drivers/EventAnimationDriver.h` ends up at `react/renderer/animated/EventAnimationDriver.h` instead of `react/renderer/animated/event_drivers/EventAnimationDriver.h`.

The `#include` in `NativeAnimatedNodesManager.h` expects the full path with the `event_drivers/` subdirectory, so the build fails with:

```
'react/renderer/animated/event_drivers/EventAnimationDriver.h' file not found
```

<img width="1512" height="1012" alt="Screenshot 2026-03-19 at 13 54 29" src="https://github.com/user-attachments/assets/49361c39-d48f-494f-ad7a-c9f3e9749a67" />

This doesn't affect prebuilt (`RCT_USE_PREBUILT_RNCORE=1`) builds because the xcframework ships with a VFS overlay that maps headers correctly.

The fix adds `header_mappings_dir` to the `animated` subspec in `React-Fabric.podspec`, which tells CocoaPods to preserve the directory structure relative to `react/renderer/animated`.

## Changelog:

[IOS] [FIXED] - Fix `EventAnimationDriver.h` not found when building React Native from source due to missing `header_mappings_dir` in `React-Fabric/animated` podspec

Pull Request resolved: react#56151

Test Plan:
1. Set `RCT_USE_PREBUILT_RNCORE=0` in your Podfile
2. Run `pod install`
3. Build the project — previously fails with `'react/renderer/animated/event_drivers/EventAnimationDriver.h' file not found`
4. With this fix, the build succeeds

Reviewed By: sammy-SC

Differential Revision: D97295771

Pulled By: zeyap

fbshipit-source-id: 945fbdeef1d25cedbec1e5b2d60c5a940da85840
…eact#56215)

Summary:
When testing React Native nightlies, we got the following error from `react-android-0.86.0-nightly-20260325-d1809f0aa-SNAPSHOT-release`:

```
StateWrapperImpl.h:14:10: fatal error: 'react/uimanager/StateWrapper.h' file not found
```

The reason is that build.gradle.kts exports src/main/jni/react/fabric → react/fabric/ in the prefab headers, which includes StateWrapperImpl.h. That header does #include <react/uimanager/StateWrapper.h>, but src/main/jni/react/uimanager is not in the prefab export list — so the header is missing from the AAR.

This was introduced in react#55288 where they modified StateWrapperImpl.h to inherit from StateWrapper and added the #include on StateWrapper.h.

This has caused Expo's nightlies to break due to the missing header file in the prefabs:

- Internally (when RN builds itself): Works fine because all JNI source dirs are on the include path
- Externally (when consumers use the published AAR): StateWrapperImpl.h is included in the prefab, it references <react/uimanager/StateWrapper.h>, but that header doesn't exist in the prefab package

## Fix

This commit fixes the above problem by including `src/main/jni/react/uimanager` in the prefab.

## Changelog
[Internal] -

Pull Request resolved: react#56215

Test Plan:
I have tested and verified this by running this in the root of the repo:

```
./gradlew :packages:react-native:ReactAndroid:preparePrefab
ls packages/react-native/ReactAndroid/build/prefab-headers/reactnative/react/uimanager/
```

Before the fix the uimanager folder was not found, with the fix it exists and contains the following files: ComponentNameResolverBinding.h  StateWrapper.h  UIConstantsProviderBinding.h

## Changelog:

[ANDROID] [FIXED] - Fixed missing StateWrapper.h header in prefabs

## Potential Issues

There might be an issue with exporting these files in addition to the missing StateWrapper.h - but it seems like this is an issue with other folders in the jni / prefab - everything in a folder is exported when included for prefab.

Reviewed By: alanleedev

Differential Revision: D98124025

Pulled By: cipolleschi

fbshipit-source-id: c8ae35e77652b90477d17ea8cab48ce3ee84d067
#publish-packages-to-npm&next
react-native-bot and others added 15 commits March 30, 2026 17:50
#publish-packages-to-npm&latest
…hanged outputs (react#55532)

Summary:
> Side-note: I've been maintaining branches to test these changes for 3 months since around 0.83/0.84, but was waiting for other changes in `scripts/codegen` to stabilise and for 0.84 to land to not interfere with other changes, and to instead target 0.85.

Currently, the codegen scripts seem to interfere with Xcode's caching. This can be validated against any app by closing and re-opening Xcode and rebuilding an app that's already been built. Many source files and libraries affected by codegen will start re-building from scratch, skipping the cache.

The changes in react@c029032 skip writing to a temporary path and let the codegen script directly write to the output paths, since `moveOutputs` calling `cp` is skipped.

However, the codegen scripts still write and copy files to the output directory, even if they exist and haven't changed. This change will replace `writeFileSync` and `cpSync` calls with wrappers that skip writing if the target exists and is identical.

## Changelog:

[IOS] [INTERNAL] - Skip writing codegen outputs when outputs are unchanged

Pull Request resolved: react#55532

Test Plan:
I've been mainly testing this in [`expo/expo`'s `notification-tester`](https://github.com/expo/expo/tree/main/apps/notification-tester) since it's a small app with few dependencies and builds relatively quickly for testing.
- Build: etc, `pod install`, `xed ios`, build in Xcode
- Rebuild (ground-truth): close and re-open Xcode, build again
- Copy new scripts into `node_modules/react-native/scripts/codegen/generate-artifacts-executor`
- Rebuild: close and re-open Xcode, build again
- Rebuild (2): close and re-open Xcode, build again

The re-build timings and target files can then be compared between "Rebuild (ground-truth)" and "Rebuild (2)". The latter will have a very high cache-hit rate and the build completes in about ~10s (instead of ~20s) skipping almost all compilation.

I've verified that running `pod install` with the new scripts still works. The re-built files in that case are identical between the old and new scripts.

Reviewed By: cortinico

Differential Revision: D93099065

Pulled By: cipolleschi

fbshipit-source-id: c3da043935d7056990b11204868aaa62ce6b0f7d
Summary:
So  the formData Upload in fetch is broken on 0.85 on main.
I tracked down this PR react#55456
Also reported here react#56404
RCA:-
```
body.isOneShot()
body.writeTo(buffer)  // This is  draining inner file InputStreams
```
Fix is to walk to each children of multipart and check for Oneshot
## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
[ANDROID][FIXED] - FormData uploads broken in debug builds

Pull Request resolved: react#56406

Test Plan:
Tested on RN tester
<img width="416" height="600" alt="image" src="https://github.com/user-attachments/assets/20cae662-e2ba-4fc7-9f8d-d8e365eb95b2" />

Reviewed By: fabriziocucci, huntie

Differential Revision: D100258994

Pulled By: alanleedev

fbshipit-source-id: aeda47d45db2152027598c949f0e602a586c4cb3
#publish-packages-to-npm&latest
Summary:
Pull Request resolved: react#56401

Add `pushAnimationMutations(Callback)` to the AnimationBackend as a targeted alternative to `trigger()`.

The existing `trigger()` method has two problems:

1. **Blast radius**: It calls `onAnimationFrame()` which invokes ALL registered callbacks. When one animation frontend (e.g. Animated) calls `trigger()` in response to an event, every other frontend (e.g. Reanimated) also spins up unnecessarily.

2. **Broken timestamp on iOS**: `trigger()` uses `std::chrono::steady_clock` which on iOS maps to a different kernel clock than what `CADisplayLink` uses for vsync timestamps. These clocks have different baselines and can diverge over time (e.g. after device sleep), causing animations to see time jumps.

`pushAnimationMutations(Callback)` fixes both issues:
- Executes only the provided callback, not all registered ones
- Uses `AnimationChoreographer::now()` which delegates to `HighResTimeStamp`, providing a timestamp from the same clock as the vsync path on each platform

Also refactors `onAnimationFrame` to use `unpackMutations`/`applySurfaceUpdates` helpers, avoiding intermediate vector/set merging when accumulating mutations from multiple callbacks.

[General][Added] - Add pushAnimationMutations to AnimationBackend for targeted event-driven animation updates

Reviewed By: zeyap

Differential Revision: D100164749

fbshipit-source-id: 53d36ed316614baa835707a45361ae8f3b828d26
…e possible (react#56465)

Summary:
Pull Request resolved: react#56465

The `cloneProps` function in `AnimationBackend.cpp` was using `std::move(*animatedProps.rawProps)` inside a `shadowTree.commit()` transaction lambda. Since commits can be retried (when `currentRevision_.number != oldRevision.number`), the moved-from `RawProps` would be in an unspecified state on the second attempt, leading to incorrect or undefined behavior.

When `enableFabricCommitBranching` is enabled, commit retries are not a concern, so moving is safe. When disabled, we now copy via `RawProps(*animatedProps.rawProps)` instead.

This is the only dangerous move in the animation backend commit path. The `AnimationBackendCommitHook` already copies correctly (`RawProps(*snapshot->rawProps)`), and `AnimatedPropsRegistry::getMap()` is safe because moved pending data persists in the `map` member across retries.

Changelog: [General][Fixed] - Fix potential data corruption in animation backend when ShadowTree commits are retried by copying RawProps instead of moving them

Reviewed By: zeyap

Differential Revision: D101161363

fbshipit-source-id: 43b9277f37563098c8ba878777d7a3099bdf1373
#publish-packages-to-npm&latest
Summary:
Pull Request resolved: react#55919

Changelog: [internal]

Adds a new feature flag to enable the experimental and partial implementation of `MutationObserver`

Reviewed By: Abbondanzo, sammy-SC, javache

Differential Revision: D95223862

fbshipit-source-id: e19dd163e5f7fecd9ef28b79be61455f0993a3c4
@rubennorte rubennorte requested a review from huntie April 24, 2026 14:38
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Apr 24, 2026
@rubennorte rubennorte closed this Apr 24, 2026
@github-actions

Copy link
Copy Markdown

Warning

JavaScript API change detected

This PR commits an update to ReactNativeApi.d.ts, indicating a change to React Native's public JavaScript API.

  • Please include a clear changelog message.
  • This change will be subject to additional review.

This change was flagged as: POTENTIALLY_BREAKING

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.