shadowlist icon indicating copy to clipboard operation
shadowlist copied to clipboard

[Android] onPress event aren't triggered in long list

Open FightFarewellFearless opened this issue 1 year ago • 25 comments

List items are rendered outside of parent height and the TouchableOpacity's onPress event aren't triggered

I'm using shadowlist v0.4.22 with react-native-screens v4.4.0 and @react-navigation/stack

Screenshot

Shadowlist bug

Code:

      <View style={[styles.container, {backgroundColor: thumbnailColor}]}>
        <Shadowlist
          data={data.episodeList.map((item, index) => ({ ...item, id: index.toString() }))}
          renderItem={() => (
            <TouchableOpacity style={styles.episodeButton} onPress={() => {
              console.log('onPress')
              props.navigation.navigate('FromUrl', {
                link: stringify('link'),
              })
            }}>
              <Text style={[globalStyles.text, styles.episodeText, { color: complementThumbnailColor }]}>
                {stringify('title')}
              </Text>
            </TouchableOpacity>
          )}
          keyExtractor={item => item.id}
           />
        </View>

FightFarewellFearless avatar Jan 11 '25 10:01 FightFarewellFearless

Hey @FightFarewellFearless,

Thanks for testing this out and sharing your report! I tried to reproduce the layout issue with navigation and screens, but I couldn’t get it to break (navigation react-navigation v7, react-native-screens v4.5). Could you provide some reproduction steps or at least share the styles you're using? It’s likely the problem is with layout calculations or adjustments which I'm willing to fix.

Screenshot 2025-01-12 at 13 04 06 Screenshot 2025-01-12 at 13 04 06

azimgd avatar Jan 12 '25 08:01 azimgd

However, I was able to reproduce the bug where the onPress event isn't triggered. It happens when you click on any appended or prepended elements after scrolling in my case. They seem to lose their InstanceHandle reference, which prevents the events from being dispatched. I’ll look into potential solutions for this.

azimgd avatar Jan 12 '25 08:01 azimgd

Im not sure what is causing the layout issue, im testing on react-native 0.76.5, and even with simple flex: 1 style, it breaks in my case, i'll try to reproduce this in a minimal template. And for the onPress issue, in my case it's not getting triggered every time, even with a very basic Touchable component

FightFarewellFearless avatar Jan 12 '25 08:01 FightFarewellFearless

Btw, what react-native version are you using?

FightFarewellFearless avatar Jan 12 '25 08:01 FightFarewellFearless

And for the onPress issue, in my case it's not getting triggered every time, even with a very basic Touchable component

Yes, I was able to reproduce this in the latest version.

https://github.com/azimgd/shadowlist/blob/3ab6449118d3ce4f68f1cdd0b8500bb5a318237f/example/package.json#L15

azimgd avatar Jan 12 '25 09:01 azimgd

I've tried the latest version u just published, and the issue is still there, even with the example code:

Code in the example folder

import { useRef, useCallback, useEffect } from 'react';
import { View, StyleSheet, Text, Pressable } from 'react-native';
import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
import {
  Shadowlist,
  type OnStartReached,
  type OnEndReached,
  type OnVisibleChange,
  type OnScroll,
  type ShadowlistProps,
  type SLContainerRef,
} from 'shadowlist';

const ITEMS_COUNT = 50;
const IS_INVERTED = false;
const IS_HORIZONTAL = false;
const INITIAL_SCROLL_INDEX = 0;
const FINAL_SCROLL_INDEX = 0;

const ListHeaderComponent = () => (
  <View style={styles.static}>
    <Text style={styles.text}>Header</Text>
  </View>
);

const ListFooterComponent = () => (
  <View style={styles.static}>
    <Text style={styles.text}>Footer</Text>
  </View>
);

const ListEmptyComponent = () => (
  <View style={styles.static}>
    <Text style={styles.text}>Empty</Text>
  </View>
);

export default function App() {
  const data = new Array(ITEMS_COUNT).fill(0).map((_, index) => ({
    id: index.toString(),
  }));
  const ref = useRef<SLContainerRef>(null);

  useEffect(() => {
    if (!FINAL_SCROLL_INDEX) return;
    setTimeout(() => {
      ref.current?.scrollToIndex({ index: FINAL_SCROLL_INDEX });
    }, 1000);
  }, []);

  const onVisibleChange = useCallback<DirectEventHandler<OnVisibleChange>>(
    (event) => {
      event.nativeEvent.visibleEndIndex;
    },
    []
  );

  const onScroll = useCallback<DirectEventHandler<OnScroll>>((event) => {
    event.nativeEvent.contentOffset.y;
  }, []);

  const renderItem: ShadowlistProps['renderItem'] = () => {
    return (
      <Pressable onPress={() => { console.log('onPress') }}>
        <Text  style={styles.text}>{`{{id}}`}</Text>
      </Pressable>
  );
  };

  return (
    <View style={styles.container}>
      <Shadowlist
        ref={ref}
        renderItem={renderItem}
        data={data}
        keyExtractor={(item) => item.id}
        onVisibleChange={onVisibleChange}
        onScroll={onScroll}
        ListHeaderComponent={ListHeaderComponent}
        ListHeaderComponentStyle={styles.static}
        ListFooterComponent={ListFooterComponent}
        ListFooterComponentStyle={styles.static}
        ListEmptyComponent={ListEmptyComponent}
        ListEmptyComponentStyle={styles.static}
        inverted={IS_INVERTED}
        horizontal={IS_HORIZONTAL}
        initialScrollIndex={INITIAL_SCROLL_INDEX}
        numColumns={1}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#333333',
    paddingTop: 60,
  },
  text: {
    color: '#333333',
    backgroundColor: '#1dd1a1',
    padding: 16,
  },
  static: {
    height: 120,
    backgroundColor: '#576574',
  },
});

I still have the onPress problem and i think the layout issue too, i think some of my dependencies are conflicting with shadowlist? not sure. I'll try with clean project

FightFarewellFearless avatar Jan 12 '25 09:01 FightFarewellFearless

Thanks for the update, this is what I get on my end which seems to layout fine?

Android example Screenshot 2025-01-12 at 14 38 21

azimgd avatar Jan 12 '25 09:01 azimgd

Thanks for the update, this is what I get on my end which seems to layout fine?

try changing the height of the container

FightFarewellFearless avatar Jan 12 '25 09:01 FightFarewellFearless

I see it now, thanks!

azimgd avatar Jan 12 '25 09:01 azimgd

import { useRef, useCallback, useEffect } from 'react';
import { View, StyleSheet, Text, Pressable } from 'react-native';
import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
import {
  Shadowlist,
  type OnStartReached,
  type OnEndReached,
  type OnVisibleChange,
  type OnScroll,
  type ShadowlistProps,
  type SLContainerRef,
} from 'shadowlist';

const ITEMS_COUNT = 50;
const IS_INVERTED = false;
const IS_HORIZONTAL = false;
const INITIAL_SCROLL_INDEX = 0;
const FINAL_SCROLL_INDEX = 0;

const ListHeaderComponent = () => (
  <View style={styles.static}>
    <Text style={styles.text}>Header</Text>
  </View>
);

const ListFooterComponent = () => (
  <View style={styles.static}>
    <Text style={styles.text}>Footer</Text>
  </View>
);

const ListEmptyComponent = () => (
  <View style={styles.static}>
    <Text style={styles.text}>Empty</Text>
  </View>
);

export default function App() {
  const data = new Array(ITEMS_COUNT).fill(0).map((_, index) => ({
    id: index.toString(),
  }));
  const ref = useRef<SLContainerRef>(null);

  useEffect(() => {
    if (!FINAL_SCROLL_INDEX) return;
    setTimeout(() => {
      ref.current?.scrollToIndex({ index: FINAL_SCROLL_INDEX });
    }, 1000);
  }, []);

  const onVisibleChange = useCallback<DirectEventHandler<OnVisibleChange>>(
    (event) => {
      event.nativeEvent.visibleEndIndex;
    },
    []
  );

  const onScroll = useCallback<DirectEventHandler<OnScroll>>((event) => {
    event.nativeEvent.contentOffset.y;
  }, []);

  const renderItem: ShadowlistProps['renderItem'] = () => {
    return (
      <Pressable onPress={() => { console.log('onPress') }}>
        <Text  style={styles.text}>{`{{id}}`}</Text>
      </Pressable>
  );
  };

  return (
    <View style={styles.container}>
      <Shadowlist
        ref={ref}
        renderItem={renderItem}
        data={data}
        keyExtractor={(item) => item.id}
        onVisibleChange={onVisibleChange}
        onScroll={onScroll}
        ListHeaderComponent={ListHeaderComponent}
        ListHeaderComponentStyle={styles.static}
        ListFooterComponent={ListFooterComponent}
        ListFooterComponentStyle={styles.static}
        ListEmptyComponent={ListEmptyComponent}
        ListEmptyComponentStyle={styles.static}
        inverted={IS_INVERTED}
        horizontal={IS_HORIZONTAL}
        initialScrollIndex={INITIAL_SCROLL_INDEX}
        numColumns={1}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    height: 120,
    backgroundColor: '#333333',
    paddingTop: 60,
    borderWidth: 8,
    borderColor: 'red',
  },
  text: {
    color: '#333333',
    backgroundColor: '#1dd1a1',
    padding: 16,
  },
  static: {
    height: 120,
    backgroundColor: '#576574',
  },
});

FightFarewellFearless avatar Jan 12 '25 09:01 FightFarewellFearless

Screenshot_20250112_164417_AniFlix Here's what i got

FightFarewellFearless avatar Jan 12 '25 09:01 FightFarewellFearless

Trying to overscroll the list seems to "fix" the layout temporarily

Screenshot_20250112_164517_AniFlix

FightFarewellFearless avatar Jan 12 '25 09:01 FightFarewellFearless

I see it now, thanks!

Do you still need a minimal repro template?

FightFarewellFearless avatar Jan 12 '25 09:01 FightFarewellFearless

I'll create one if you want

FightFarewellFearless avatar Jan 12 '25 09:01 FightFarewellFearless

Nope, thank you @FightFarewellFearless. I'll let you know once fixed.

azimgd avatar Jan 12 '25 10:01 azimgd

Thank you very much @azimgd

FightFarewellFearless avatar Jan 12 '25 10:01 FightFarewellFearless

Hey @FightFarewellFearless, this should be fixed on 0.4.24

azimgd avatar Jan 13 '25 16:01 azimgd

Hey @FightFarewellFearless, this should be fixed on 0.4.24

Thanks! i'll try this on the weekend. Thank you for making this awesome library!

FightFarewellFearless avatar Jan 13 '25 22:01 FightFarewellFearless

Hey @FightFarewellFearless, this should be fixed on 0.4.24

Hello @azimgd, just tried this update recently and the onPress bug aren't fully fixed. Let say i have a very big list with at least 500 items, let say, the first 100 item's onPress event is triggered, but the rest item is not getting triggered, i think this is because of the press state or something similar, you can try with TouchableOpacity and scroll through the long list, notice the opacity isn't change at the initial list, but when you continue scrolling, the opacity of the touchable is changed and get stucked (see the screenshot below)

FightFarewellFearless avatar Jan 14 '25 11:01 FightFarewellFearless

Screenshot_20250114_185312_AniFlix

FightFarewellFearless avatar Jan 14 '25 11:01 FightFarewellFearless

I started a discussion here to get more insights. Interestingly, this is reproducible on Android but not on iOS. I’m working on getting it fixed soon.

azimgd avatar Jan 26 '25 18:01 azimgd

Thank you, can't wait for this library to become stable 🚀🚀

FightFarewellFearless avatar Jan 29 '25 07:01 FightFarewellFearless

Hey @FightFarewellFearless, I merged a PR with the fix couple of days ago. I plan to deploy the new version by the end of this week.

azimgd avatar Feb 19 '25 17:02 azimgd

👍

FightFarewellFearless avatar Feb 20 '25 06:02 FightFarewellFearless

Hey @FightFarewellFearless, I merged a PR with the fix couple of days ago. I plan to deploy the new version by the end of this week.

Just tested your dynamic-components branch—the onPress issue is fixed, but the opacity issue with Touchable still persists. I also found another styling-related issue: the list height doesn’t account for React Navigation’s bottom tabs. In other words, the list extends beyond the visible area when using bottom tabs. I tried adding paddingBottom and marginBottom to the list style, but that didn’t fix the issue.

FightFarewellFearless avatar Mar 03 '25 07:03 FightFarewellFearless