Skip to content

Commit a3f11e4

Browse files
pawicaoclaude
andcommitted
Fix differ creating or deleting a view that a nested (un)flattening moves
When a view flattens in the same commit in which its parent unflattens, a child with a negative zIndex is sorted before the view that contains it. The final loop of calculateShadowViewMutationsFlattener then took it for a new or removed view, because the nested recursion matched it through a different ShadowViewNodePair. Skip candidates the recursion recorded in the sub-visited map. Also stop keeping a pointer to a loop-local copy in unvisitedRecursiveChildPairs. Fixes #58647 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent d950a46 commit a3f11e4

1 file changed

Lines changed: 9 additions & 3 deletions

File tree

‎packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.cpp‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -708,9 +708,9 @@ static void calculateShadowViewMutationsFlattener(
708708
auto unvisitedOtherNodesIt =
709709
unvisitedOtherNodes.find(newChild.shadowView.tag);
710710
if (unvisitedOtherNodesIt != unvisitedOtherNodes.end()) {
711-
auto unvisitedItPair = *unvisitedOtherNodesIt->second;
711+
auto* unvisitedItPair = unvisitedOtherNodesIt->second;
712712
unvisitedRecursiveChildPairs.insert(
713-
{unvisitedItPair.shadowView.tag, &unvisitedItPair});
713+
{unvisitedItPair->shadowView.tag, unvisitedItPair});
714714
} else {
715715
unvisitedRecursiveChildPairs.insert(
716716
{newChild.shadowView.tag, &newChild});
@@ -820,6 +820,9 @@ static void calculateShadowViewMutationsFlattener(
820820
// Final step: go through creation/deletion candidates and delete/create
821821
// subtrees if they were never visited during the execution of the above
822822
// loop and recursions.
823+
const auto& subVisitedMap = reparentMode == ReparentMode::Flatten
824+
? *subVisitedOldMap
825+
: *subVisitedNewMap;
823826
for (auto& deletionCreationCandidatePair : deletionCreationCandidatePairs) {
824827
auto& treeChildPair = *deletionCreationCandidatePair.second;
825828

@@ -828,7 +831,10 @@ static void calculateShadowViewMutationsFlattener(
828831
// already created/deleted and we don't need to do that here.
829832
// It is always the responsibility of the matcher to update subtrees when
830833
// nodes are matched.
831-
if (treeChildPair.inOtherTree()) {
834+
// The recursion can match the node through a different pair instance
835+
// (e.g. when zIndex orders it before its parent), so check its tag too.
836+
if (treeChildPair.inOtherTree() ||
837+
subVisitedMap.contains(treeChildPair.shadowView.tag)) {
832838
continue;
833839
}
834840

0 commit comments

Comments
 (0)