diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp index 438e03851137..f4e2ca37637e 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp @@ -30,12 +30,12 @@ void ReanimatedMountHook::shadowTreeDidMount( auto reaShadowNode = std::reinterpret_pointer_cast( std::const_pointer_cast(rootShadowNode)); + // We mark reanimated commits with ReanimatedMountTrait. We don't want other + // shadow nodes to use this trait, but since this rootShadowNode is Shared, + // we don't have that guarantee. That's why we also unset this trait in the + // commit hook. We remove it here mainly for the sake of cleanliness. const bool isReanimatedMount = reaShadowNode->hasReanimatedMountTrait(); if (isReanimatedMount) { - // We mark reanimated commits with ReanimatedMountTrait. We don't want other - // shadow nodes to use this trait, but since this rootShadowNode is Shared, - // we don't have that guarantee. That's why we also unset this trait in the - // commit hook. We remove it here mainly for the sake of cleanliness. reaShadowNode->unsetReanimatedMountTrait(); } @@ -44,17 +44,19 @@ void ReanimatedMountHook::shadowTreeDidMount( // Record the mounted tree for relative-length resolution. viewStylesRepository_->setLastMountedRoot(rootShadowNode); - if (isReanimatedMount) { - return; - } - + // Always drain removable nodes, even on Reanimated's own commits. While CSS + // animations run every mount carries the mount trait, so returning early here + // would skip removals for the whole animation and leak unmounted nodes if the + // tree is torn down mid-animation. updatesRegistryManager_->handleNodeRemovals(*rootShadowNode); - // When commit from React Native has finished, we reset the skip commit flag - // in order to allow Reanimated to commit its tree - updatesRegistryManager_->unpauseReanimatedCommits(); - if (updatesRegistryManager_->shouldCommitAfterPause()) { - requestFlush_(); + if (!isReanimatedMount) { + // When a commit from React Native has finished, we reset the skip commit + // flag in order to allow Reanimated to commit its tree. + updatesRegistryManager_->unpauseReanimatedCommits(); + if (updatesRegistryManager_->shouldCommitAfterPause()) { + requestFlush_(); + } } } }