Skip to content

feat(Reanimated): route synchronous prop updates to the light tree - #10416

Open
pawicao wants to merge 9 commits into
mainfrom
@pawicao/lighttree-sync-update-props
Open

feat(Reanimated): route synchronous prop updates to the light tree#10416
pawicao wants to merge 9 commits into
mainfrom
@pawicao/lighttree-sync-update-props

Conversation

@pawicao

@pawicao pawicao commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Note

This pull request was authored by AI on behalf of @pawicao.

Summary

The experimental layout animations proxy keeps a light tree as its model of the mounted views. Until now only pullTransaction fed it. Props applied through synchronouslyUpdateUIProps skip the shadow tree and pullTransaction, so the light tree never saw them. When a shared element held a transform applied through that path, the transition snapshot appeared at the untransformed layout position. That is why we didn't allow having both *_SYNCHRONOUSLY_UPDATE_UI_PROPS and ENABLE_SHARED_ELEMENT_TRANSITIONS flags enabled at the same time.

Feeding the light tree

  • A new virtual, applySynchronousProps (no-op in the common LA proxy base), merges each synchronous update into the matching LightNode under the proxy mutex, through the component descriptor.
  • applySynchronousUpdates calls it after partitionUpdates, so both sync paths feed the tree — performOperations and the Android draw pass — before the native views get the new values.

Keeping the merge across commits (iOS)

On iOS the merge alone does not survive. The Update branch of updateLightTree replaces the stored props with the committed ones, and commits do not carry the synchronous values: React receives them only through the settled sync-back, about one second after a value stops changing. Inside that window every commit that touches the view — even a plain relayout — erased the merge.

The proxy now keeps the last synchronous props per tag (synchronousPropsOverlay_) and puts them back after each replacement. This is the same rule mounting and the commit hook already enforce elsewhere: a commit must not clobber props the animated registry owns. The overlay lives exactly as long as that ownership:

  • collectSettledUpdates reports the tags it evicts and getSettledUpdates relays them to dropSynchronousProps.
  • A Delete mutation erases the entry.
  • Important exception: Updates flushed by the CSS registries stay out of the overlay — nothing manages their lifetime — so performOperations collects their tags and the proxy skips and erases them.

Android needs no overlay: its Update branch merges raw props. (that, as I understand, can change in the future)

Removed guards

The bypass is gone, so the guards that kept the synchronous-update flags and ENABLE_SHARED_ELEMENT_TRANSITIONS apart are removed:

  • the shouldUseSynchronousUpdatesInPerformOperations conjuncts,
  • the pod install assertion,
  • the Gradle assertion.

Recordings

Before

before02.mov

After

after02.mov

Test plan

Two new examples in fabric-example, run with ENABLE_SHARED_ELEMENT_TRANSITIONS and the platform's synchronous-updates flag on:

  • [SET] Animated Transform — a box with a static style transform (translateX: 60) and a box whose transform comes from a non-animating useAnimatedStyle (translateX: 80, set once on mount, so it reaches the native view only through the synchronous path). Both transitions must start from the shifted positions.
  • [SET] Light Tree Erasure Repro — both buttons shift a box to a marked frame and navigate 250 ms later; the second also triggers an unrelated commit in between. Without the overlay the second transition started from the layout frame; both must start from the shifted frame.

Verified:

  1. iOS, lldb — applySynchronousProps fires on mount (pre-merge transform.matrix[12] = 0), and startSharedTransition receives before-snapshots with matrix[12] = 60 and 80; the back transition shows the same values on the after side.
  2. iOS, manual — both examples, forward and back, with the flag on and off.
  3. Android emulator, frame-by-frame pixel tracing of screen recordings — every transition starts from and returns to the transformed position; both erasure buttons start from the shifted frame; no react_native_assert aborts in logcat.

Changelog

  • I added an entry to the Unpublished section of each changed package's CHANGELOG.md, or this PR does not change react-native-reanimated or react-native-worklets.

@pawicao
pawicao force-pushed the @pawicao/lighttree-sync-update-props branch from a9587fd to de78feb Compare August 26, 2026 07:31
@pawicao pawicao changed the title feat(SET): route synchronous prop updates to the light tree feat(Reanimated): route synchronous prop updates to the light tree Aug 26, 2026
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b0d6047b-9487-4c9f-8790-f002ab7957e9

📥 Commits

Reviewing files that changed from the base of the PR and between e88fd5a and 51689f0.

📒 Files selected for processing (1)
  • apps/common-app/src/apps/reanimated/examples/SharedElementTransitions/LightTreeErasure.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/common-app/src/apps/reanimated/examples/SharedElementTransitions/LightTreeErasure.tsx

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The change forwards synchronous UI prop updates to the experimental layout animation light tree. It tracks, reapplies, skips, and removes synchronous-props overlays. It reports evicted tags and permits synchronous-update feature flags with shared element transitions on Android and iOS. It adds animated transform and light-tree erasure examples with native-stack navigation and shared-transition boundaries, then registers both examples for iOS and Android.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description clearly explains routing synchronous UI prop updates into the experimental layout animations light tree, the shared-element transition fix, implementation details, removed guards, and …
Title check ✅ Passed The title clearly and concisely summarizes the primary change: routing synchronous prop updates to the Reanimated light tree.
Full details: Description check

Explanation

The description clearly explains routing synchronous UI prop updates into the experimental layout animations light tree, the shared-element transition fix, implementation details, removed guards, and verification steps.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 49214958-e0f5-4a14-a49e-b544abf048f3

📥 Commits

Reviewing files that changed from the base of the PR and between 404c564 and de78feb.

⛔ Files ignored due to path filters (1)
  • apps/fabric-example/ios/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • apps/common-app/src/apps/reanimated/examples/SharedElementTransitions/AnimatedTransform.tsx
  • apps/common-app/src/apps/reanimated/examples/index.ts
  • apps/fabric-example/package.json
  • packages/react-native-reanimated/CHANGELOG.md
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.h
  • packages/react-native-reanimated/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp
  • packages/react-native-reanimated/android/build.gradle.kts
  • packages/react-native-reanimated/scripts/reanimated_utils.rb
💤 Files with no reviewable changes (2)
  • packages/react-native-reanimated/android/build.gradle.kts
  • packages/react-native-reanimated/scripts/reanimated_utils.rb

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.

@pawicao
pawicao force-pushed the @pawicao/lighttree-sync-update-props branch from 01a1638 to d79fc2b Compare August 26, 2026 09:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp (1)

268-278: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard the Delete lookup before dereferencing the iterator.

handleSubtreeRemoval can call endAnimationsRecursively, which erases the tag from lightNodes_ before updateLightTree processes a later input Delete for the same tag. In release builds, react_native_assert does not stop execution, so it->second dereferences lightNodes_.end() and can crash the transaction. Add an it == lightNodes_.end() guard before accessing it->second.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fbe012bc-2737-46d1-b344-ddf9676c2483

📥 Commits

Reviewing files that changed from the base of the PR and between 01a1638 and d79fc2b.

📒 Files selected for processing (3)
  • packages/react-native-reanimated/CHANGELOG.md
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.h
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/react-native-reanimated/CHANGELOG.md

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5841de32-d88e-4883-b532-3a89fb5d44ab

📥 Commits

Reviewing files that changed from the base of the PR and between d79fc2b and e88fd5a.

📒 Files selected for processing (9)
  • apps/common-app/src/apps/reanimated/examples/SharedElementTransitions/LightTreeErasure.tsx
  • apps/common-app/src/apps/reanimated/examples/index.ts
  • packages/react-native-reanimated/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.h
  • packages/react-native-reanimated/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.h

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.

@pawicao
pawicao marked this pull request as ready for review August 27, 2026 10:11
@pawicao
pawicao force-pushed the @pawicao/lighttree-sync-update-props branch 2 times, most recently from 01088b4 to ae39ad2 Compare August 27, 2026 11:13
On iOS, a commit that does not carry the synchronous props replaced
the merged light tree props. Keep the last synchronous props for each
animated view and put them back after such a commit. Drop them when
the settled values reach React state or when the view is deleted.
Updates from the CSS registries stay out of this store because no
eviction path manages their lifetime.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant