Skip to content

[BUG] Clicking first item causes unexpected scroll/visual glitch when item moves to end of list #380

@blazejkustra

Description

@blazejkustra

Description

When clicking on the first visible item in a LegendList (which triggers a state update that moves the item to the end of the data array), there's unexpected visual behavior on both web and iOS platforms.

Expected Behavior

When an item is pressed and moved to the end of the list via state update, the list should update without any visual glitches or unexpected scroll position changes.

Actual Behavior

Clicking on the first item causes weird visual behavior - the list appears to jump or glitch when the item is moved to the end of the data array.

web:

web.mov

ios:

ios.MP4

Reproduction

import React, { useCallback, useState } from 'react';
import { View, StyleSheet, Text, Pressable } from 'react-native';
import { LegendList } from '@legendapp/list';

type Item = {
  id: string;
  name: string;
};

const initialData: Item[] = Array.from({ length: 50 }, (_, i) => ({
  id: String(i + 1),
  name: `Item ${i + 1}`,
}));

function MinimalReproduction() {
  const [data, setData] = useState(initialData);

  const handleScroll = useCallback(() => {
    // scroll handler
  }, []);

  const handleRefresh = useCallback(() => {
    // refresh handler
  }, []);

  const handleItemPress = useCallback((item: Item) => {
    setData((prev) => {
      const filtered = prev.filter((i) => i.id !== item.id);
      return [...filtered, item];
    });
  }, []);

  const renderItem = useCallback(
    ({ item }: { item: Item }) => (
      <Pressable style={styles.item} onPress={() => handleItemPress(item)}>
        <Text style={styles.itemText}>{item.name}</Text>
      </Pressable>
    ),
    [handleItemPress],
  );

  return (
    <View style={styles.container}>
      <LegendList
        contentContainerStyle={styles.contentContainer}
        ListHeaderComponent={<View style={styles.header} />}
        onScroll={handleScroll}
        scrollEventThrottle={16}
        keyboardDismissMode="on-drag"
        refreshing={false}
        onRefresh={handleRefresh}
        data={data}
        renderItem={renderItem}
        keyExtractor={(item: Item) => item.id}
        recycleItems
        maintainVisibleContentPosition
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  contentContainer: {
    padding: 16,
  },
  header: {
    height: 100,
  },
  item: {
    height: 50,
    marginBottom: 8,
    backgroundColor: '#eee',
    justifyContent: 'center',
    paddingHorizontal: 16,
  },
  itemText: {
    fontSize: 16,
  },
});

export default MinimalReproduction;

Steps to Reproduce

  1. Render the component above
  2. Click/tap on the first visible item in the list
  3. Observe the visual glitch/jump as the item is moved to the end

Environment

  • Platforms affected: Web, iOS (possibly android too)
  • version: v2.0.19

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions