dillon1000/react

Commit

Add parentEnter/parentExit props to ViewTransition (#36690)

An alternative to https://github.com/facebook/react/pull/36135

___

Adds experimental support for `parentEnter` and `parentExit` on nested
`<ViewTransition>` components, so descendants can animate when an
ancestor boundary enters or exits.

This is gated behind the `enableViewTransitionParentEnterExit` feature
flag.

Addresses the use case of animating individual items in a list (such as
sliding inactive feed posts off-screen) when a parent `<ViewTransition>`
is the one being added or removed during the update.

Today, `exit`/ `enter` only fire on the `<ViewTransition>` that was
directly mounted or unmounted. Nested boundaries in the same subtree are
not visited for their own `exit`/`enter` when the whole tree goes away
as one unit, which is usually what you want. But some cases need an
explicit opt-in to nested animations.

This PR adds `parentEnter`/`parentExit`, and their handlers
`onParentEnter`/`onParentExit`. When an ancestor runs a real `enter` or
`exit`, React walks descendants and activates boundaries that define the
nested props. This only continues through `<ViewTransition>` nodes that
define `parentEnter` / `parentExit` / `onParentEnter` / `onParentExit` /
`onGestureParentEnter` / `onGestureParentExit`, otherwise the chaining
stops. A boundary’s own `enter`/`exit` still do not run when only an
ancestor animates. So it is possible to have different animations on the
same `<ViewTransition>` for `enter` vs `parentEnter`.

```jsx
function ExampleOnAncestorExit() {
  return (
    // This boundary exits — starts the parentExit walk
    <ViewTransition exit="panel-exit">
      <div>
        {/* ✓ Activates: parentExit set. Walk continues inside */}
        <ViewTransition parentExit="slide-out">
          <div>
            {/* ✗ parentEnter is not consulted on an exit walk */}
            <ViewTransition parentEnter="slide-in">
              ...
            </ViewTransition>
            {/* ✗ Chain broken: no parentExit or onParentExit */}
            <ViewTransition>
              <div>
                {/* ✗ Never reached on this path, blocked by parent above */}
                <ViewTransition parentExit="slide-out">
                  ...
                </ViewTransition>
              </div>
            </ViewTransition>
            {/* ✓ Handler-only chain: onParentExit continues the walk */}
            <ViewTransition onParentExit={() => animateOut()}>
              <ViewTransition onParentExit={() => animateDeepOut()}>
                ...
              </ViewTransition>
            </ViewTransition>
            {/* ✓ Activates: sibling under the chain */}
            <ViewTransition parentExit="slide-out">
              ...
            </ViewTransition>
          </div>
        </ViewTransition>
      </div>
    </ViewTransition>
  );
}
```
Browse files
Changed paths17 files
First-parent comparison
A fixtures/view-transition/src/components/NestedParentExit.css AddedA fixtures/view-transition/src/components/NestedParentExit.js AddedM fixtures/view-transition/src/components/Page.js ModifiedM packages/react-dom/src/__tests__/ReactDOMViewTransition-test.js ModifiedM packages/react-reconciler/src/ReactFiberApplyGesture.js ModifiedM packages/react-reconciler/src/ReactFiberCommitViewTransitions.js ModifiedM packages/react-reconciler/src/ReactFiberCompleteWork.js ModifiedM packages/react-reconciler/src/ReactFiberFlags.js ModifiedM packages/shared/ReactFeatureFlags.js ModifiedM packages/shared/ReactTypes.js ModifiedM packages/shared/forks/ReactFeatureFlags.native-fb.js ModifiedM packages/shared/forks/ReactFeatureFlags.native-oss.js ModifiedM packages/shared/forks/ReactFeatureFlags.test-renderer.js ModifiedM packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js ModifiedM packages/shared/forks/ReactFeatureFlags.test-renderer.www.js ModifiedM packages/shared/forks/ReactFeatureFlags.www-dynamic.js ModifiedM packages/shared/forks/ReactFeatureFlags.www.js Modified
Patch

Files changed

Rendering syntax-highlighted changes…