Skip to content

fix(LayoutAnimations): update Android view hierarchy only during JS pulls - #10372

Open
bartlomiejbloniarz wants to merge 1 commit into
yzm/04-progress-lifecyclefrom
yzm/05-android-js-pull-cleanup
Open

fix(LayoutAnimations): update Android view hierarchy only during JS pulls#10372
bartlomiejbloniarz wants to merge 1 commit into
yzm/04-progress-lifecyclefrom
yzm/05-android-js-pull-cleanup

Conversation

@bartlomiejbloniarz

@bartlomiejbloniarz bartlomiejbloniarz commented Aug 21, 2026

Copy link
Copy Markdown
Member

This issue only exists on Android. Before this change, Reanimated could observe pullTransaction calls in one order while Android converted and applied them in another. A React transaction could first pass through pullTransaction on the JS thread and move to a local pending vector. Before its executeMount started, animation completion could cause another pullTransaction on the UI thread. The UI path calls scheduleMountItem and tryDispatchMountItems synchronously, so its cleanup changes the View Hierarchy immediately. The React path calls scheduleMountItem from the JS thread, which only queues its MountItem for a later UI-thread dispatch. Remove or Delete mutations could therefore use child indices for a hierarchy that React had not mounted yet.

obraz

On Android, shouldFlushStructuralMutations now blocks hierarchy cleanup during UI-thread pulls. maybeScheduleCleanupPull keeps the work pending and requests one later JS-thread pull. This creates a clear Android-only boundary: React queues its transaction first, then Reanimated queues the hierarchy cleanup. Their MountItems now reach the UI thread in the same order. Other platforms keep the existing behavior.

Threading analysis

AI analysis, mostly for future reference

Test Plan

  • Run ExperimentalCleanupOrderingExample on Android.
  • Repeat the cleanup sequence with Experimental layout animations enabled.
  • Build and run the existing layout animation examples on iOS.

@coderabbitai

coderabbitai Bot commented Aug 21, 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: b238bf51-6294-4b63-8bdb-18999bf20c31

📥 Commits

Reviewing files that changed from the base of the PR and between a057f29 and 8d90c09.

📒 Files selected for processing (4)
  • apps/common-app/src/apps/reanimated/examples/index.ts
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h

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


📝 Walkthrough

Walkthrough

Adds Android-aware deferral and scheduling for structural layout-animation cleanup. Extends completed-animation cleanup to preserve selected tags. Adds an experimental example that repeatedly replaces animated items, periodically stalls the UI thread, and provides Start and Stop controls. Registers the example in the layout-animation examples map.

🚥 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.
Title check ✅ Passed The title clearly identifies the Android LayoutAnimations fix and the change to update the view hierarchy only during JS pulls.
Description check ✅ Passed The description directly explains the Android transaction-ordering issue, the cleanup changes, and the related test plan.

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.

@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from cdd2123 to c591edb Compare August 24, 2026 07:58
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from c591edb to e7d893d Compare August 24, 2026 14:11
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch 2 times, most recently from 7994a7f to 5bb5ef1 Compare August 24, 2026 15:38
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from 5bb5ef1 to d53260a Compare August 24, 2026 15:45
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch 2 times, most recently from b772e2d to 8502c9a Compare August 24, 2026 15:53
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from 8502c9a to 82eb4f7 Compare August 24, 2026 15:56
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from 82eb4f7 to a057f29 Compare August 24, 2026 16:03
@bartlomiejbloniarz

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch 2 times, most recently from 8d90c09 to f42bcc6 Compare August 25, 2026 14:23
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from f42bcc6 to e821045 Compare August 26, 2026 08:55
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from e821045 to d3ee84d Compare August 26, 2026 09:36
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch 2 times, most recently from 195223f to 55f1107 Compare August 26, 2026 15:42
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from 55f1107 to c0bf038 Compare August 27, 2026 09:21
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch 2 times, most recently from 65d0c62 to c81a201 Compare August 28, 2026 16:01
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch 2 times, most recently from 672d049 to 71a7474 Compare August 31, 2026 10:00
Android's push model applies React transactions from the JS thread
asynchronously on the UI thread. An Experimental completion pull can run on
the UI thread and synchronously mount its Remove/Delete mutations first,
leaving React's queued transaction with stale child indices.

Keep completed exiting nodes and shared-transition containers pending during
UI-thread pulls. A debounced JS-thread pull performs those structural
removals in React transaction order, while non-structural final updates still
reconcile immediately. The gate is Android-only and can be removed with the
pull model.

Add an Experimental cleanup-ordering stress example. With the gate bypassed,
it reproduces addViewAt index/count failures; with the fix it runs through
more than 1,800 cycles and clears all exiting views after Stop.


fix(Android): reset the cleanup-pull debounce on surface teardown
@bartlomiejbloniarz
bartlomiejbloniarz force-pushed the yzm/05-android-js-pull-cleanup branch from 71a7474 to 32506fd Compare August 31, 2026 12:28
@bartlomiejbloniarz
bartlomiejbloniarz marked this pull request as ready for review August 31, 2026 13:29
filteredMutations.end(), transaction.teardownMutations.begin(), transaction.teardownMutations.end());

flushCompletedRemovals(filteredMutations);
flushCompletedRemovals(filteredMutations, flushStructuralMutations);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

hmm wouldn't it be somehow simpler to just do

  if (!flushStructuralMutations) {
    flushCompletedRemovals(filteredMutations);
  }

since flushStructuralMutations is just used as an early return in the beginning of that function?

@pawicao pawicao Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

oh unless the reasoning is to have similar API shape of flushCompletedRemovals as cleanupAnimations that has to use flushStructuralMutations inside, then I understand

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.

2 participants