Repository: facebook/react
Pull request: Mark shouldStartViewTransition as true when there's an enter animation

Typically we mark the name of things that might animate in the snapshot phase. At the same time we track that should call startViewTransition too. However, we don't do this for "enter" since they're only marked later. Leading to having just an "enter" not to animate unless there's at least another update too.

This tracks if there's a ViewTransitionComponent in the tree that enters. Luckily we know that from the static flag so we don't have to traverse it.

Changed files:
filename: packages/react-reconciler/src/ReactFiberCommitViewTransitions.js
patch: @@ -67,6 +67,20 @@ export function trackAppearingViewTransition(
   appearingViewTransitions.set(name, state);
 }
 
+export function trackEnterViewTransitions(placement: Fiber): void {
+  if (
+    placement.tag === ViewTransitionComponent ||
+    (placement.subtreeFlags & ViewTransitionStatic) !== NoFlags
+  ) {
+    // If an inserted or appearing Fiber is a ViewTransition component or has one as
+    // an immediate child, then that will trigger as an "Enter" in future passes.
+    // We don't do anything else for that case in the "before mutation" phase but we
+    // still have to mark it as needing to call startViewTransition if nothing else
+    // updates.
+    shouldStartViewTransition = true;
+  }
+}
+
 // We can't cancel view transition children until we know that their parent also
 // don't need to transition.
 export let viewTransitionCancelableChildren: null | Array<
@@ -119,7 +133,6 @@ function applyViewTransitionToHostInstancesRecursive(
   let inViewport = false;
   while (child !== null) {
     if (child.tag === HostComponent) {
-      shouldStartViewTransition = true;
       const instance: Instance = child.stateNode;
       if (collectMeasurements !== null) {
         const measurement = measureInstance(instance);
@@ -132,6 +145,7 @@ function applyViewTransitionToHostInstancesRecursive(
           inViewport = true;
         }
       }
+      shouldStartViewTransition = true;
       applyViewTransitionName(
         instance,
         viewTransitionHostInstanceIdx === 0

filename: packages/react-reconciler/src/ReactFiberCommitWork.js
patch: @@ -235,6 +235,7 @@ import {
   commitFragmentInstanceInsertionEffects,
 } from './ReactFiberCommitHostEffects';
 import {
+  trackEnterViewTransitions,
   commitEnterViewTransitions,
   commitExitViewTransitions,
   commitBeforeUpdateViewTransition,
@@ -338,6 +339,9 @@ function commitBeforeMutationEffects_begin(isViewTransitionEligible: boolean) {
       // to trigger updates of any nested view transitions and we shouldn't
       // have any other before mutation effects since snapshot effects are
       // only applied to updates. TODO: Model this using only flags.
+      if (isViewTransitionEligible) {
+        trackEnterViewTransitions(fiber);
+      }
       commitBeforeMutationEffects_complete(isViewTransitionEligible);
       continue;
     }
@@ -367,6 +371,9 @@ function commitBeforeMutationEffects_begin(isViewTransitionEligible: boolean) {
           // to trigger updates of any nested view transitions and we shouldn't
           // have any other before mutation effects since snapshot effects are
           // only applied to updates. TODO: Model this using only flags.
+          if (isViewTransitionEligible) {
+            trackEnterViewTransitions(fiber);
+          }
           commitBeforeMutationEffects_complete(isViewTransitionEligible);
           continue;
         }