Skip to content

Commit 9b33e75

Browse files
ehsemlohfacebook-github-bot
authored andcommitted
fixed (iOS) Relayout not Working for Nested Inline (#41352)
Summary: React Native, the text inline is made versatile by design. Being managed in an alien layout logic (i.e., text paragraph), inline views work seamlessly as if in normal **flex** layout. The capacities such as animation and relayout, however, requires extra efforts on native layer. This PR fixed one critical issue for inline, i.e., `setState()` is not working when inline contains nested views. Closes #41348 Demo (Fixed) https://github.com/facebook/react-native/assets/149237137/2b42d657-4024-476b-bf0c-be25ef4f8c0c ## Problem in technical: This issue is caused by a bug in `RCTShadowView::sizeThatFitsMinimumSize()` which accidentally unlink children (of yoga nodes) with their parent (owner). More specifically, on the critical path, it 1. first **shallow** clones the current node ``` YGNodeRef clonedYogaNode = YGNodeClone(self.yogaNode); ``` 2. then calls `YGNodeCalculateLayout()` using the cloned node 3. deallocate the cloned node `YGNodeFree()` One unseen implication of `YGNodeFree()` is to unlink all its children (because of the **shallow** clone) ``` for (size_t i = 0; i < childCount; i++) { auto child = node->getChild(i); child->setOwner(nullptr); } ``` Next, let's examine, **How nullptr of owner can cause the broken `setState()` of nested inline views** The orphan children has two consequences: **a**. the changes on child node (`setState()`) cannot be propagated to the parent (`YGNodeMarkDirty` -> `node->markDirtyAndPropagate();`); **b**. `YGNodeCalculateLayout()` (`yoga::calculateLayoutImpl`) will create new children instances when orphan is detected (see below) ``` node->cloneChildrenIfNeeded(); // line 1599 # CalculateLayout.cpp ``` Both compounded are contributing the failed `setState()`. Respectively, **a** causes early return of `YGNodeCalculateLayout()` because parent is recognized as not *dirty*; **b** clones a new *dirty* node which replaces the child which is supposed to be *cleaned* within `YGNodeCalculateLayout()`. And this is the *dirty* node detected by the assertion mentioned in the issue description #41348. ## The fix: The fix introduced in this PR is to relink the children with their parent in `RCTShadowView::sizeThatFitsMinimumSize()` ## Changelog: [IOS] [FIXED] - `setState` is not working for nested inline views in text Pull Request resolved: #41352 Test Plan: Test directly in rn-tester TBD Reviewed By: yungsters Differential Revision: D51071338 Pulled By: NickGerleman fbshipit-source-id: 1f3d8a3e1e03cb11577f903e43f2c2cce9e07b6e
1 parent 94da17e commit 9b33e75

File tree

1 file changed

+7
-0
lines changed

1 file changed

+7
-0
lines changed

packages/react-native/React/Views/RCTShadowView.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,13 @@ - (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximu
366366
YGNodeFree(constraintYogaNode);
367367
YGNodeFree(clonedYogaNode);
368368

369+
// `setOwner()` for children unlinked by `YGNodeFree()`
370+
int childCount = YGNodeGetChildCount(self.yogaNode);
371+
for (int i = 0; i < childCount; i++) {
372+
YGNodeRef child = YGNodeGetChild(self.yogaNode, i);
373+
YGNodeSwapChild(self.yogaNode, child, i);
374+
}
375+
369376
return measuredSize;
370377
}
371378

0 commit comments

Comments
 (0)