react-native-draggable-flatlist icon indicating copy to clipboard operation
react-native-draggable-flatlist copied to clipboard

Flicker Issue in New Arch

Open amthirukumaran opened this issue 5 months ago • 15 comments

My project has react-native-draggable-flatlist": "^4.0.3 react-native-gesture-handler": "^2.25.0 react-native-reanimated": "^3.17.0

And My Code is <DraggableFlatList data={productData ?? []} keyExtractor={(item: { id: number }) => item?.id.toString()} renderItem={renderItem} containerStyle={{ flex: 1 }} onRelease={() => setTimeout(() => setTransparentLoad(true))} onDragEnd={({ data }) => { if (JSON?.stringify(productData) != JSON.stringify(data)) { setProductData(data); dispatch(setIsDirtyPage(true)); setTimeout(() => { setIsChanged(true); setTransparentLoad(false); }); } else { // Use a timeout here too, to avoid layout jitter setTimeout(() => setTransparentLoad(false), 50); } }} autoscrollSpeed={150} autoscrollThreshold={80} showsVerticalScrollIndicator={false} contentContainerStyle={{ flex: productData?.length ? undefined : 1, paddingBottom: productData?.length ? 100 : undefined }} ListEmptyComponent={<ListEmpty image={"no-featured-products.png"} text={translate("NO_PRODUCTS_TEXT")} />} />

And my render Item is const renderItem = ({ item, drag, index }: any) => { return ( <ScaleDecorator> <TouchableOpacity key={index} onPress={() => { selectProducts({ id: item?.id }) }} style={{ flex: 1, marginHorizontal: 13, marginTop: 15, paddingHorizontal: width > 600 ? 20 : 10, paddingVertical: width > 600 ? 10 : 5, borderWidth: item?.select ? 1.1 : 1, borderRadius: 5, borderColor: item?.select ? appColors?.primary : appColors?.borderColor }}> <View style={{ flex: 1, flexDirection: "row", justifyContent: "space-between", gap: 10, backgroundColor: "" }}> <View style={{ flex: 1, flexDirection: "row", gap: 20, alignItems: "center", backgroundColor: "" }}> <Image style={{ height: 60, width: 60 }} source={{ uri: config.AWSImageUrl + (item?.featuredImage ?? "mobileAdmin/no-image.jpg") }} resizeMode="contain" resizeMethod='resize' PlaceholderContent={ <Image style={{ height: 60, width: 60 }} source={{ uri: config?.AWSImageUrl + "mobileAdmin/no-image.jpg" }} resizeMode="contain" resizeMethod='resize' /> } /> <View style={{ flex: 1 }}> <Text ellipsizeMode="tail" numberOfLines={2} style={{ color: appColors?.primary, flexWrap: "wrap", fontFamily: appFonts?.bold, fontSize: smallerFontSize }}>{item?.name?.replace(/\s+/g, " ")}</Text> <Text style={{ fontSize: tinyFontSize, color: appColors?.lightDark, fontFamily: appFonts?.bold }}>{${translate("PRICE")} : }{CommonService?.currencyFormatter(item?.price)}</Text> </View> </View> <TouchableOpacity hitSlop={{ bottom: 10, left: 10, right: 10, top: 10 }} onPressIn={() => !item?.select ? drag() : undefined} style={{ backgroundColor: "", justifyContent: "center", flex: 0.15, alignItems: "flex-end", marginRight: 10 }}> {item?.select ? <MaterialCommunityIcons name={'check-circle'} color={appColors?.checkCircleGreen} size={22} /> : <MaterialCommunityIcons name="drag-horizontal-variant" color={appColors?.iconColor} size={25} /> } </TouchableOpacity> </View> </TouchableOpacity> </ScaleDecorator > ) }

And I Attached Video

https://github.com/user-attachments/assets/0687cf58-c9c6-4c22-8414-5c1588e1544d

amthirukumaran avatar Jul 17 '25 09:07 amthirukumaran

I second this. I forked the library and tried to fix it on my own but was unable to. Also, I verified that this is caused by the library and not a bad implementation on my part because I tested it with the exact example provided in the npm page and I got the same behaviour. (I'm talking about the nestableDraggableFlatList Example.

For context, my implementation looks a bit like this: <NestableDraggableContainer> <NestableDraggableFlatList renderItem={workoutCards} onDragEnd={()=> reorderWorkoutCards}

    />

And the renderItemItself contains a nestableDraggableFlatlist inside it (when it is opened to show the sets). renderItem.jsx: <NestableDraggableFlatList renderItem={sets} onDragEnd={()=> reorderSets} />

https://github.com/user-attachments/assets/b6c84962-ff37-4074-bb8f-7a4e63c497c2

maboul6 avatar Jul 17 '25 17:07 maboul6

is there any way to solve the glitch

amthirukumaran avatar Jul 21 '25 07:07 amthirukumaran

Same issue here

Sydney-o9 avatar Jul 26 '25 11:07 Sydney-o9

temporary downgrade to 4.0.2 work for me

builam66 avatar Jul 28 '25 08:07 builam66

don't know if that helps, but messing around this issue i found ` const onDragEnd = useStableCallback( ({ from, to }: { from: number; to: number }) => { const { onDragEnd, data } = props;

  const newData = [...data];
  if (from !== to) {
    newData.splice(from, 1);
    newData.splice(to, 0, data[from]);
  }

  // TODO: this line causes flickering for me
  onDragEnd?.({ from, to, data: newData });

  setActiveKey(null);
}

);`

inside node_modules/react-native-draggable-flatlist/src/components/DraggableFlatList.tsx

after disabling onDragEnd we lose order & positions of items on screen, but flickering doesn't happen anymore. I assume problem is with how data updated for a FlatList. Maybe that helps somebody

dimafarafonov avatar Jul 30 '25 08:07 dimafarafonov

Any solutions?

c-info avatar Aug 01 '25 11:08 c-info

Same issue, hopefully a fix will be released :)

Kober-L avatar Aug 08 '25 18:08 Kober-L

Yes, same issue on our end, it used to work fine, but now there is a lot of visual glitches, either with 4.0.2 or 4.0.3

Daavidaviid avatar Aug 11 '25 16:08 Daavidaviid

Add the index into the keyExtractor worked for me.

const keyExtractor = useCallback((item: any, index: number) => `${item.id}-${index}`, []);

<DraggableFlatList
  keyExtractor={keyExtractor}
  ...otherProps
/>

notmarinho avatar Aug 12 '25 15:08 notmarinho

Add the index into the keyExtractor worked for me.

const keyExtractor = useCallback((item: any, index: number) => `${item.id}-${index}`, []);

<DraggableFlatList
  keyExtractor={keyExtractor}
  ...otherProps
/>

thanks for the optimize rerendering..

amthirukumaran avatar Aug 12 '25 16:08 amthirukumaran

seems to be helping a bit ! But I don tunderstand why, do you mind to give more details ?

Kober-L avatar Aug 12 '25 17:08 Kober-L

Even using this keyExtractor technique, I noticed it seems to still flicker on the first drag and drop

Daavidaviid avatar Aug 12 '25 17:08 Daavidaviid

Despite the keyExtractor technique, I still get the flicker on each drag'n'drop operation. Will try downgrading a lib.

angusryer avatar Aug 26 '25 18:08 angusryer

I decided to build the drag-and-drop myself using Reanimated 4.

At first, reading the code from this library made it seem quite complicated, but I managed to get a fully working example on iOS, Android, and Web in under 170 lines of code.

Here’s a gist you can copy and paste into your project: https://gist.github.com/Daavidaviid/32a06e47cde1eae50bad5b5677e9dbc8

You can adapt it to your use case, or leave a comment if you spot an issue so I can improve it.
(I thought creating a gist made more sense than publishing a library in this case.)

Daavidaviid avatar Aug 30 '25 15:08 Daavidaviid

Add the index into the keyExtractor worked for me.

const keyExtractor = useCallback((item: any, index: number) => `${item.id}-${index}`, []);

<DraggableFlatList
  keyExtractor={keyExtractor}
  ...otherProps
/>

This causes re-render every component between the re-ordered two items.

Kaosc avatar Sep 12 '25 08:09 Kaosc

Add the index into the keyExtractor worked for me.

const keyExtractor = useCallback((item: any, index: number) => `${item.id}-${index}`, []);

<DraggableFlatList
  keyExtractor={keyExtractor}
  ...otherProps
/>

MY HERO!!!

My code snippet:

<DraggableFlatList<Ingredient> data={ingredients} onDragEnd={({ data }) => setIngredients(data)} keyExtractor={(item, index) => ${item.id}-${index}} renderItem={renderIngredientItem} contentContainerStyle={{ paddingBottom: 20 }} animationConfig={{ damping: 20, mass: 0.2, stiffness: 100, overshootClamping: true }} showsVerticalScrollIndicator={false} keyboardShouldPersistTaps="handled" ListHeaderComponent={

Ichiritzu avatar Dec 26 '25 16:12 Ichiritzu