Skip to content

Fix recycled ScrollView inheriting stale contentInset on iOS#56832

Open
cbrevik wants to merge 1 commit into
facebook:mainfrom
cbrevik:fix-scrollview-stale-inset
Open

Fix recycled ScrollView inheriting stale contentInset on iOS#56832
cbrevik wants to merge 1 commit into
facebook:mainfrom
cbrevik:fix-scrollview-stale-inset

Conversation

@cbrevik
Copy link
Copy Markdown
Contributor

@cbrevik cbrevik commented May 14, 2026

Summary:

Fixes #55090

In Fabric, prepareForRecycle resets contentInset to zero when a ScrollView is recycled. But the subsequent frame reset dance (required for contentInsetAdjustmentBehavior see 27fe6f1) triggers centerContentIfNeeded with the previous component's stale content size, silently overwriting the reset.

As a result, a ScrollView with centerContent={true} that is unmounted and replaced by another ScrollView leaves behind a stale contentInset that the new component inherits causing displaced content if the new ScrollView does not have centerContent={true}.

Two fixes:

  1. RCTScrollViewComponentView
    In updateProps, when centerContent transitions from true to false, explicitly reset contentInset to the prop value. centerContentIfNeeded will not self-correct once centerContent is disabled on the new component, so the reset must be forced. The existing contentInset prop check is also guarded with !centerContent to prevent it from overriding the inset calculated by centerContentIfNeeded when centering is active.
  2. RCTEnhancedScrollView
    Override setCenterContent: and setContentSize: to trigger centerContentIfNeeded. This ensures centering is re-applied with the correct new content size when the new component's content arrives via updateState:, and that toggling centerContent takes effect immediately.

Changelog:

[IOS] [FIXED] - Fix recycled ScrollView inheriting stale contentInset from centerContent on Fabric

Test Plan:

Using the RNTester-app, replace CenterContentList with the following inside ScrollViewExample.js:

CenterContentList reproducer Doing two different ScrollViews to force an unmount of the one with centerContent so the other inherits its insets
function CenterContentList(): React.Node {
  const [centerContent, setCenterContent] = useState(true);
  if (centerContent) {
    return (
      <ScrollView
        nestedScrollEnabled
        style={styles.scrollView}
        centerContent={true}>
        <Text>This should be in center.</Text>
        <Button
          label="Toggle centerContent"
          onPress={() => setCenterContent(!centerContent)}
        />
      </ScrollView>
    );
  } else {
    return (
      <ScrollView
        nestedScrollEnabled
        style={styles.scrollView}
        centerContent={false}>
        <Text>This should not be in center.</Text>
        <Button
          label="Toggle centerContent"
          onPress={() => setCenterContent(!centerContent)}
        />
      </ScrollView>
    );
  }
}

Before the fix

Note that for both ScrollViews the content is centered, even though one has centerContent={false}.

before-the-fix.mov

After the fix

One is properly centered, while the other has its content at the top.

after-the-fix.mov

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 14, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS] contentInset and contentOffset on recycled ScrollView is not reset on reuse

1 participant