react-native: [Android][Flatlist][Horizontal] Last item delete in horizontal flatlist does not adjust scroll position.

React Native version: 0.59.10

output

Steps To Reproduce

export default class App extends Component<Props> {

  constructor(props) {
    super(props);
    this.dataItems = [{
      id: 1,
      text: 'one'
    },{
      id: 2,
      text: 'two'
    },{
      id: 3,
      text: 'three'
    }, {
      id: 4,
      text: 'four',
    }, {
      id: 5,
      text: 'five'
    }];
  }

  removeItem = (id) => {
    this.dataItems = this.dataItems.filter((item) => item.id !== id);
    this.setState({});
  };

  renderItem = ({item}) => {
    return (
      <View style={{ width: 140, height: 140, backgroundColor: 'yellow', margin: 10}}>
        <Text>{item.text}</Text>
        <TouchableOpacity onPress={() => {
          this.removeItem(item.id);
        }}>
          <Text>{'Remove me'}</Text>
        </TouchableOpacity>
      </View>
    )
  };

  render() {
    return (
      <View style={styles.container}>
        <View style={{height: 140, width: '100%'}}>
          <FlatList
            horizontal
            data={this.dataItems}
            renderItem={this.renderItem}
            keyExtractor={item => `${item.id}`}
          />
        </View>
      </View>
    );
  }
}

Describe what you expected to happen: After removing last item, scroll position should be adjusted.

Snack, code example, screenshot, or link to a repository:

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 11
  • Comments: 26 (7 by maintainers)

Most upvoted comments

Same problem here.

A workaround while waiting fix: use scrollToEnd when removing the last item.

Example:

import React, { useState, useRef, useCallback } from "react";
import { FlatList } from "react-native";

function ExampleComponent() {
  const [items, setItems] = useState<[]>([]);
  const flatListRef = useRef<FlatList>();

  const handleRemoveFlatListItem = useCallback(
    (index: number) => {
      const canScrollToEnd = index === items.length - 1;
      const newItems = [...items] as [];
      newItems.splice(index, 1);
      setItems([...newItems]);
      if (flatListRef?.current && canScrollToEnd)
        flatListRef.current.scrollToEnd();
    },
    [items, flatListRef]
  );

  const renderItem = ...

  return (
    <FlatList
      horizontal
      data={items}
      renderItem={renderItem}
      keyExtractor={(item) => `${item.id}`}
    />
  );
}

still broken

Given this is unfixed after 3 years I just went with a workaround. 😛

In my case I’m not explicitly removing an item from a list, but rather getting updated data from an API call which could change the data in a horizontal list. If viewing the last item when this happens it will exhibit this behavior. And since I don’t explicitly know that the last item was removed (or any item to make the list shorter I guess) I just went with a more brute force approach.

I store the current content offset by observing onScrollEndDrag and onMomentumScrollEnd. And I added an onContentSizeChange callback to check for when the width changes (i.e., and item was removed). I also know the width of the items by measuring them when the items layout (if your item widths vary this would be more complicated). Finally, in a useEffect, if contentOffset + itemWidth > contentWidth then I know I’ve hit a case where this bug has happened and I’m showing past the end of the scrollview. If that is true, then call scrollToEnd (without animation in my case) on a reference to the list.

Bit of a pain, but not too bad and works for me.

So…I see this is closed, but it’s still broken. Is there another thread where it’s not closed?

The PR (https://github.com/facebook/react-native/pull/27514) has the exact fix for Horizontal Scroll View which is already present in vertical scrollview in production/master since a long time.

same problem on Android on 0.71.3

I have this issue on 0.67.4, but with a scrollview (horizontal) like:

<ScrollView>
    {array.map((item) => (
        <Item onPress={() => removeItem(item.id)} key={item.id} />
    )}
</ScrollView>

Same problem on 0.63.4