Skip to content

Commit 9edfb68

Browse files
habovhclaude
andcommitted
Mount children of a legacy view right away so its children stay in step with Fabric's
Summary: `mountChildComponentView:index:` inserted a child only when it was appended (`index == reactSubviews.count`); any other insertion was queued in `_viewsToBeMounted` until `finalizeUpdates:`, which only runs when the host view itself is updated (props, state or layout). A transaction that inserts a child before others and leaves the host view unchanged therefore left the child unmounted until some later update, and every later `index == count` check failed in the meantime, so more children were queued (the paper view's order drifted from Fabric's). With an adapter the child is now inserted at its index (clamped to the number of children) straight away, and `didUpdateReactSubviews` is called as it was for appended children. The queue is only used before the adapter exists. Changelog: [IOS] [FIXED] - LegacyViewManagerInterop mounts a child inserted before other children of a legacy view right away Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
1 parent e83e491 commit 9edfb68

1 file changed

Lines changed: 10 additions & 10 deletions

File tree

‎packages/react-native/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,18 @@ - (void)prepareForRecycle
173173

174174
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
175175
{
176-
if (_adapter && index == _adapter.paperView.reactSubviews.count) {
177-
// This is a new child view that is being added to the end of the children array.
178-
// After the children is added, we need to call didUpdateReactSubviews to make sure that it is rendered.
176+
if (_adapter) {
177+
// The child is inserted right away, wherever it goes, so that the paper view's `reactSubviews` stay in step with the
178+
// Fabric children. A mount that waited for `finalizeUpdates:` would be applied late (the host view is not updated
179+
// by every transaction that changes its children) and would shift the position of every later child.
180+
// After the child is added, we need to call didUpdateReactSubviews to make sure that it is rendered.
179181
// Without this change, the new child will not be rendered right away because the didUpdateReactSubviews is not
180182
// called and the `finalizeUpdate` is not invoked.
183+
UIView *target = childComponentView;
181184
if ([childComponentView isKindOfClass:[RCTLegacyViewManagerInteropComponentView class]]) {
182-
UIView *target = ((RCTLegacyViewManagerInteropComponentView *)childComponentView).contentView;
183-
[_adapter.paperView insertReactSubview:target atIndex:index];
184-
} else {
185-
[_adapter.paperView insertReactSubview:childComponentView atIndex:index];
185+
target = ((RCTLegacyViewManagerInteropComponentView *)childComponentView).contentView;
186186
}
187+
[_adapter.paperView insertReactSubview:target atIndex:MIN(index, (NSInteger)_adapter.paperView.reactSubviews.count)];
187188
[_adapter.paperView didUpdateReactSubviews];
188189
} else {
189190
[_viewsToBeMounted addObject:@{
@@ -195,9 +196,8 @@ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompone
195196

196197
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
197198
{
198-
// `index` is the child's position among the Fabric children. It is not its position in the paper view's
199-
// `reactSubviews` while mounts are queued in `_viewsToBeMounted`, as those are only inserted in `finalizeUpdates`.
200-
// The child named by the mutation is therefore looked up instead of trusting `index`.
199+
// The child named by the mutation is looked up instead of using `index` as a position in the paper view's
200+
// `reactSubviews`: the two differ whenever a mount is still queued in `_viewsToBeMounted`.
201201

202202
// A child whose mount is still queued never reached the paper view: forget the mount.
203203
for (NSDictionary *mountInstruction in [_viewsToBeMounted copy]) {

0 commit comments

Comments
 (0)