Skip to content

Removing item from start of data in Flatlist with maintainVisibleContentPosition results in a unwanted scroll behavior #52757

@itsramiel

Description

@itsramiel

Description

If an item is removed from the start of a Flatlist, which satisfy the following conditions:

  • data length is more than the number of rendered items. Let me elaborate on this point. To reproduce this issue, the number of item's passed need to be larger than the number rendered. So By default windowSize is 21. Assuming 10 items can be rendered per window, so number of rendered items would be 210. So if your data is of length 300(300 > 210), then it would be reproduced. In order to reproduce it with smaller data, then use a smaller windowSize
  • maintainVisibleContentPosition is set. For example: { minIndexForVisible: 0, autoscrollToTopThreshold: 10 }

then an unwanted scrolling behaviour is produced.

Example Code

import {
  Button,
  FlatList,
  ListRenderItemInfo,
  StyleSheet,
  Text,
  View,
} from 'react-native';
import { useCallback, useState } from 'react';

const INITIAL_DATA = Array.from({ length: 10000 }).map((_, i) => i);
const MAINTAIN_VISIBLE_CONTENT_POSITION = {
  minIndexForVisible: 0,
  autoscrollToTopThreshold: 10,
};

function App() {
  const [data, setData] = useState(INITIAL_DATA);

  const removeItem = useCallback(() => {
    setData(prevData => prevData.slice(1));
  }, [setData]);

  return (
    <View style={styles.screen}>
      <Button title="Remove Item" onPress={removeItem} />
      <FlatList
        style={styles.list}
        data={data}
        renderItem={renderItem}
        maintainVisibleContentPosition={MAINTAIN_VISIBLE_CONTENT_POSITION}
        keyExtractor={item => item.toString()}
      />
    </View>
  );
}

function renderItem(props: ListRenderItemInfo<number>) {
  return <ListItem {...props} />;
}

function ListItem({ item }: ListRenderItemInfo<number>) {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>{item}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  screen: {
    flex: 1,
    backgroundColor: '#fff',
    paddingTop: 48,
  },
  list: {
    flex: 1,
  },
  listContent: {
    padding: 12,
    gap: 12,
  },
  container: {
    borderWidth: 1,
    borderColor: '#000000',
    padding: 12,
    alignItems: 'center',
    justifyContent: 'center',
  },
  footerContainer: {
    flexDirection: 'row',
  },
  text: {
    fontSize: 14,
  },
  leadingFooterItem: {
    flex: 1,
    backgroundColor: 'blue',
    height: 50,
  },
  trailingFooterItem: {
    backgroundColor: 'red',
    width: 50,
    aspectRatio: 1,
  },
  buttonsContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
});

export default App;

Note that I also tested 0.82.0-nightly-20250722-2c3a00b7b as I see the same behaviour

Steps to reproduce

  1. Clone repo or initialize a new react native with the example code
  2. Press on the Remove Item
  3. Notice the weird scrolling behaviour on iOS as shown in the video below

React Native Version

0.80.1

Affected Platforms

Runtime - iOS

Areas

Fabric - The New Renderer

Output of npx @react-native-community/cli info

System:
  OS: macOS 15.5
  CPU: (14) arm64 Apple M3 Max
  Memory: 3.35 GB / 36.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.14.0
    path: ~/.nvm/versions/node/v22.14.0/bin/node
  Yarn:
    version: 1.22.22
    path: ~/.nvm/versions/node/v22.14.0/bin/yarn
  npm:
    version: 10.9.2
    path: ~/.nvm/versions/node/v22.14.0/bin/npm
  Watchman:
    version: 2025.04.14.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /Users/itsramiel/.rbenv/shims/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.5
      - iOS 18.5
      - macOS 15.5
      - tvOS 18.5
      - visionOS 2.5
      - watchOS 11.5
  Android SDK: Not Found
IDEs:
  Android Studio: 2024.3 AI-243.24978.46.2431.13363775
  Xcode:
    version: 16.4/16F6
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.10
    path: /usr/bin/javac
  Ruby:
    version: 3.4.3
    path: /Users/itsramiel/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 19.0.0
    wanted: 19.0.0
  react:
    installed: 19.1.0
    wanted: 19.1.0
  react-native:
    installed: 0.80.1
    wanted: 0.80.1
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: true

Stacktrace or Logs

There is no log for a crash or failure

MANDATORY Reproducer

https://github.com/itsramiel/FlatlistScroll

Screenshots and Videos

Screen Recording

iOS Android
Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-07-22.at.12.27.19.mp4
Screen.Recording.2025-07-22.at.12.27.24.PM.mov

I am mainly concered with the new arch as that is what I am using in my app but just for reference and in case it helps, it used to work fine on the old arch

Screen Recording(Old Arch as Reference)

iOS Android
Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-07-22.at.12.33.03.mp4
Screen.Recording.2025-07-22.at.12.33.07.PM.mov

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions