Flicker Issue in New Arch
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
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
is there any way to solve the glitch
Same issue here
temporary downgrade to 4.0.2 work for me
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
Any solutions?
Same issue, hopefully a fix will be released :)
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
Add the index into the keyExtractor worked for me.
const keyExtractor = useCallback((item: any, index: number) => `${item.id}-${index}`, []);
<DraggableFlatList
keyExtractor={keyExtractor}
...otherProps
/>
Add the
indexinto thekeyExtractorworked for me.const keyExtractor = useCallback((item: any, index: number) => `${item.id}-${index}`, []); <DraggableFlatList keyExtractor={keyExtractor} ...otherProps />
thanks for the optimize rerendering..
seems to be helping a bit ! But I don tunderstand why, do you mind to give more details ?
Even using this keyExtractor technique, I noticed it seems to still flicker on the first drag and drop
Despite the keyExtractor technique, I still get the flicker on each drag'n'drop operation. Will try downgrading a lib.
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.)
Add the
indexinto thekeyExtractorworked 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.
Add the
indexinto thekeyExtractorworked 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={