Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple onPress invocations on scroll #1461

Open
1 of 2 tasks
Tobbe opened this issue Jan 3, 2025 · 3 comments
Open
1 of 2 tasks

Multiple onPress invocations on scroll #1461

Tobbe opened this issue Jan 3, 2025 · 3 comments
Labels
bug Something isn't working

Comments

@Tobbe
Copy link

Tobbe commented Jan 3, 2025

Current behavior

With the code below I'm getting multiple onPress invocations when scrolling in the list.
It only seems to happen when the list is short enough to fit on one screen. If I include all 13 items the issue goes away and an actual click/press is required to fire the onPress event, and it's only fired once.

Here's a video of the behavior I'm seeing. Look at all those console logs. Especially the last one is weird. It keeps invoking onPress even after I stop scrolling. And I've seen that behavior many times by now

Screen.Recording.2025-01-03.at.23.14.22.mov
import React, { useState } from "react";
import { View, StyleSheet, Text, StatusBar, Pressable } from "react-native";
import { FlashList } from "@shopify/flash-list";

const DATA = [
  {
    id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
    title: "First Item",
  },
  {
    id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
    title: "Second Item",
  },
  {
    id: "58694a0f-3da1-471f-bd96-145571e29d72",
    title: "Third Item",
  },
  {
    id: "4f2b5cf1-9e9d-4e6c-b2c8-7c3a9e2d5b0a",
    title: "Fourth Item",
  },
  {
    id: "a1b2c3d4-e5f6-4a5b-8c7d-9e0f1a2b3c4d",
    title: "Fifth Item",
  },
  {
    id: "5e6f7g8h-9i0j-4k5l-6m7n-8o9p0q1r2s3",
    title: "Sixth Item",
  },
  {
    id: "t4u5v6w7-x8y9-4z1a-2b3c-4d5e6f7g8h9i",
    title: "Seventh Item",
  },
  {
    id: "j0k1l2m3-n4o5-4p6q-7r8s-9t0u1v2w3x4y",
    title: "Eighth Item",
  },
  {
    id: "z5a6b7c8-d9e0-4f1g-2h3i-4j5k6l7m8n9o",
    title: "Ninth Item",
  },
  {
    id: "p0q1r2s3-t4u5-4v6w-7x8y-9z0a1b2c3d4e",
    title: "Tenth Item",
  },
  {
    id: "f5g6h7i8-j9k0-4l1m-2n3o-4p5q6r7s8t9u",
    title: "Eleventh Item",
  },
  {
    id: "v0w1x2y3-z4a5-4b6c-7d8e-9f0g1h2i3j4k",
    title: "Twelfth Item",
  },
  {
    id: "l5m6n7o8-p9q0-4r1s-2t3u-4v5w6x7y8z9a",
    title: "Thirteenth Item",
  },
].slice(0, 3);

const App = () => {
  const [selectedId, setSelectedId] = useState<string | null>(null);

  return (
    <View style={styles.container}>
      <FlashList
        data={DATA}
        renderItem={({ item }) => {
          return (
            <ListItem
              item={item}
              selectedId={selectedId}
              setSelectedId={setSelectedId}
            />
          );
        }}
        keyExtractor={(item) => item.id}
        extraData={selectedId}
        estimatedItemSize={48}
      />
    </View>
  );
};

interface ListeItemProps {
  item: { id: string; title: string };
  selectedId: string | null;
  setSelectedId: (id: string) => void;
}

const ListItem = ({ item, selectedId, setSelectedId }: ListeItemProps) => {
  const backgroundColor = item.id === selectedId ? "#6e3b6e" : "#f9c2ff";
  const color = item.id === selectedId ? "white" : "black";

  return (
    <Pressable
      onPress={() => {
        setSelectedId(item.id);
        console.log({ item });
      }}
      style={[styles.item, { backgroundColor }]}
    >
      <Text style={[styles.title, { color }]}>{item.title}</Text>
    </Pressable>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: StatusBar.currentHeight || 0,
  },
  item: {
    backgroundColor: "#f9c2ff",
    padding: 20,
    marginVertical: 8,
    marginHorizontal: 16,
  },
  title: {
    fontSize: 32,
  },
});

export default App;

Expected behavior

I expect scrolling to do nothing when the list is short enough to not require any scrolling to display all items. No onPress actions should be fired when scrolling

To Reproduce

Run the code above and scroll in the list.

So far I've only tried to reproduce this in an Android Emulator.
I'm using expo and it seems to happen both with Expo Go and with a proper dev build of the app.
The behavior is the same both with new and old architecture
I'm scrolling using a two-finger gesture on my touchpad.

Platform:

  • iOS
  • Android

Environment

1.7.1

@Tobbe Tobbe added the bug Something isn't working label Jan 3, 2025
@Tobbe
Copy link
Author

Tobbe commented Jan 4, 2025

After adding some more logging I'm seeing this:
Image

And that's just from a single scroll motion/action

@Tobbe
Copy link
Author

Tobbe commented Jan 4, 2025

Workaround for now (still only tested in the Android emulator)

// Keep these outside the component so we can track clicks across all list
// items
let clickCount = 0;
let clickTime = 0;

export const SingleItem = ({ item }: SingleItemProps) => {
  const router = useRouter();

  return (
    <Pressable
      onPressIn={() => {
        if (Date.now() - clickTime > 500) {
          clickCount = 0;
        }

        clickTime = Date.now();
        clickCount++;
      }}
      onPressOut={() => {
        if (clickCount !== 1) {
          return;
        }

        router.push({
          pathname: LINKS.MY_SINGLE_ITEM,
          params: { id: item.id },
        });
      }}
    >

  // ... etc

@Tobbe
Copy link
Author

Tobbe commented Jan 4, 2025

I think it's actually a RN issue
facebook/react-native#27355

If you all agree it's on the RN crew to fix this then we can close this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant