react-native-draggable-flatlist
react-native-draggable-flatlist copied to clipboard
Expo SDK 52 upgrade breaks animations
Describe the bug After an upgrade to Expo SDK version 52, and all relevant dependencies, a previously working horizontal draggable flatlist exhibits two incorrect behaviors:
- Drag and drop rearranging the values of the list works, but upon drop, the entries flash back to their original order for a second before settling in the final, correct positions. This make the rearranging feel and look extremely jittery.
- With the drag and drop, the item we are dragging sometimes does not resize back down to its normal size after being dropped, leading to an oversized item in the lift. Screenshot of this is attached.
Full code of the component is attached below.
Platform & Dependencies Please list any applicable dependencies in addition to those below (react-navigation etc).
- react-native-draggable-flatlist version: ^4.0.1
- Platform: ios
- React Native or Expo version: expo 52.0.4
- Reanimated version: 3.16.1
- React Native Gesture Handler version: ~2.20.2
- React Native version: 0.76.1
Previous Platform & Dependencies where this code worked
- react-native-draggable-flatlist version: ^4.0.1
- Platform: ios
- React Native or Expo version: expo 51.0.6
- Reanimated version: ~3.10.1
- React Native Gesture Handler version: ^2.16.1
- React Native version: 0.74.1
const Favorites = ({ favoriteBooks, isLoading, navigation, onReorder, isCurrentUser, userDetails }) => {
const { theme } = useContext(ThemeContext);
const styles = getDynamicStyles(theme);
const [isEditMode, setIsEditMode] = useState(false);
const [data, setData] = useState(favoriteBooks);
useEffect(() => {
setData(favoriteBooks);
}, [favoriteBooks]);
const LibraryButton = () => (
<TouchableOpacity
onPress={() => navigation.navigate('Library', {
userDetails: userDetails
})}
style={[
styles.libraryButton,
{ opacity: isLoading ? 0.5 : 1 }
]}
disabled={isLoading}
>
<Ionicons
name="library-outline"
size={15}
color={theme.distinctAccentColor}
style={{ marginRight: 5 }}
/>
<Text style={[styles.libraryButtonText, { color: theme.distinctAccentColor }]}>
{isLoading ? 'Loading...' : 'View Library'}
</Text>
</TouchableOpacity>
);
const toggleEditMode = async () => {
if (isCurrentUser) {
if (isEditMode) {
// Exiting edit mode, save the new order
const newOrder = data.map(item => item.id);
try {
const result = await BookService.reorderFavorites(newOrder);
if (result) {
onReorder(newOrder);
setIsEditMode(false);
} else {
Alert.alert("Error", "Failed to save the new order. Please try again.");
}
} catch (error) {
console.error('Error saving favorites order:', error);
Alert.alert("Error", "An error occurred while saving. Please try again.");
}
} else {
// Entering edit mode
setIsEditMode(true);
}
}
};
useEffect(() => {
console.log("Setting navigation options. isEditMode:", isEditMode);
navigation.setOptions({
swipeEnabled: !isEditMode,
});
}, [isEditMode, navigation]);
const renderPlaceholderCard = () => {
return (
<View style={styles.placeholderCard}>
<Ionicons name="sparkles-outline" size={24} color={theme.subtleAccentColor} />
<Text style={styles.placeholderText}>Future Gem</Text>
</View>
);
};
const handleDragStart = useCallback(() => {
console.log("Drag started");
}, []);
const handleDragEnd = useCallback(({ data: newData, from, to }) => {
console.log("Drag ended. From:", from, "To:", to);
console.log("New data order:", newData.map(item => item.id));
setData(newData);
onReorder(newData.map(item => item.id));
}, [onReorder]);
const renderBookItem = useCallback(({ item, drag, isActive }) => {
if (item === 'placeholder') {
return renderPlaceholderCard();
}
if (isLoading) {
return (
<View style={styles.bookItem}>
<ShimmerPlaceholder
width={styles.thumbnail.width}
height={styles.thumbnail.height}
style={styles.thumbnail}
/>
<View style={[styles.bookTitle, { height: 16 }]} />
<View style={[styles.bookAuthor, { height: 12 }]} />
</View>
);
}
const book = item.book;
const navigateToBookDetails = () => {
if (!isEditMode) {
navigation.navigate('BookDetails', { book });
}
};
return (
<TouchableOpacity
onPress={navigateToBookDetails}
onLongPress={() => {
console.log("Long press detected on book:", book.title, "isEditMode:", isEditMode);
if (isEditMode) {
console.log("Initiating drag for book:", book.title);
drag();
}
}}
style={[
styles.bookItem,
isActive && styles.activeBookItem,
]}
>
<Image source={{ uri: book.cover_url }} style={styles.thumbnail} />
<Text allowFontScaling={false} style={styles.bookTitle}>{truncate(book.title, 15)}</Text>
<Text allowFontScaling={false} style={styles.bookAuthor}>{truncate(book.author, 15)}</Text>
</TouchableOpacity>
);
}, [isEditMode, isLoading, navigation, styles, theme]);
const favoritesList = isLoading
? [1, 2, 3, 4, 5]
: [...data];
while (favoritesList.length < 5) {
favoritesList.push('placeholder');
}
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<View style={styles.favoritesContainer}>
<View style={styles.favoritesHeaderContainer}>
<Text allowFontScaling={false} style={styles.favoritesHeader}>Favorites</Text>
{!isCurrentUser && <LibraryButton />}
{isCurrentUser && (
<TouchableOpacity onPress={toggleEditMode} style={styles.editButton}>
<Ionicons
name={isEditMode ? "save-outline" : "pencil-outline"}
size={20}
color={theme.mainTextColor}
/>
</TouchableOpacity>
)}
</View>
<DraggableFlatList
data={favoritesList}
renderItem={renderBookItem}
keyExtractor={(item, index) => {
if (isLoading) return `loading-${index}`;
if (item === 'placeholder') return `placeholder-${index}`;
return item.id ? item.id.toString() : `item-${index}`;
}}
horizontal
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
showsHorizontalScrollIndicator={false}
style={styles.favoritesFlatList}
contentContainerStyle={styles.favoritesContent}
ItemSeparatorComponent={() => <View style={styles.favoritesItemSeparator} />}
activationDistance={0}
dragItemOverflow={true}
dragHitSlop={{ top: 10, bottom: 10, left: 20, right: 20 }}
autoscrollThreshold={20}
autoscrollSpeed={100}
/>
<View style={styles.swipeGuideContainer}>
<Icon name="arrow-back" size={15} color={theme.subtleAccentColor} />
<Icon name="arrow-forward" size={15} color={theme.subtleAccentColor} />
</View>
</View>
</GestureHandlerRootView>
);
};`
Same here. After upgrading to Expo SDK 52 and rn reanimated to 3.16.1 (as required per Expo), experiencing the identical issue. It's reproducible in a fresh new barebones project. Also, react native's LayoutAnimation seems to have no effect also after the upgrade (I'm rearranging by list upon a button click)
This mainly because of new arch, you can set newArchEnabled to false so the animation works normally
Unfortunately, that does not solve it @shorkyyy. It was the first thing I tried when I ran into the issue and I just retried it again. I ensured that I ran a clean build by resetting everything, and both issues I described above still persist.
Same problem here.
"react-native-draggable-flatlist": "^4.0.1", "react-native": "^0.76.1", "react-native-reanimated": "^3.6.0",
Same problem here.
"react-native-draggable-flatlist": "^4.0.1", "react-native": "0.76.2", "react-native-reanimated": "~3.16.1",
0.5x
https://github.com/user-attachments/assets/69121f5c-8ebb-44e7-8336-5b071ba5938d
+1 for the video @Unuuuuu, this is exactly what I am seeing as well
Also I'm seeing a lot of console errors during the dragging.
(NOBRIDGE) WARN [Reanimated] Tried to modify key `current` of an object which has been already passed to a worklet. See
https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#tried-to-modify-key-of-an-object-which-has-been-converted-to-a-shareable
for more details.
Yes @fonodi I am seeing the same. You can silence these warnings for the meantime, but I bet they are somehow involved in this behavior
Unfortunately, that does not solve it @shorkyyy. It was the first thing I tried when I ran into the issue and I just retried it again. I ensured that I ran a clean build by resetting everything, and both issues I described above still persist.
Haven't tested on sdk52 yet but I have tested it on sdk51 and when I enable newarch, the same issue appears and I had no clue what's wrong with it, so I cloned my project and set newarch = false and the issue disappears
I have similar glitches in the same situation on sdk 52 with the new architecture enabled. When I disable the new architecture it works much better but still I get the same messages as @fonodi :
Also I'm seeing a lot of console errors during the dragging.
(NOBRIDGE) WARN [Reanimated] Tried to modify key `current` of an object which has been already passed to a worklet. See https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#tried-to-modify-key-of-an-object-which-has-been-converted-to-a-shareable for more details.
I am also having issues since upgrading to EXPO SDK 52.
This setup doesnt work anymore. The animations are broken and I am getting this error:
(NOBRIDGE) ERROR Warning: ref.measureLayout must be called with a ref to a native component.
Managed to fix the same issue in my project with this patch, please check if it helps.
@MeNoKVN
(NOBRIDGE) ERROR Warning: ref.measureLayout must be called with a ref to a native component.
See #544
Managed to fix the same issue in my project with this patch, please check if it helps.
I applied your patch, now It's not so horrible, but I still can see some glitches...
@ddrozdov thank you for the patch! I went ahead and applied it and as @aleksey-mukho noted, there has been an improvement but not all the way.
In detail: The Good: The items flashing back to their original spot is indeed fixed by your patch. This is great step forward.
The Bad: However, now the items themselves very briefly flash on rearrange. Sometimes multiple items, not just the ones being dragged. To me this suggests that the draggable flatlist is being re-rendered.
The Ugly: The resizing issue is still present, and I still cannot reproduce it consistently. Sometimes I will drag an item and it will drop down and resize down correctly. Other times, I will drag and drop, but the item never resizes down again.
Hi @computerjazz Your project is amazing, but I think everyone is missing you 😃 Could you tell us what your plans are with the project?
Hi @computerjazz Your project is amazing, but I think everyone is missing you 😃 Could you tell us what your plans are with the project?
He mentioned his plans here https://github.com/computerjazz/react-native-draggable-flatlist/issues/542#issuecomment-2246473428
Has anyone managed to solve the problem?
I have identified the cause of the problem. In the CellRenderer Component, the transform style is updated while the element is being moved. After changing the data, new data comes to onDragEnd, but the elements that match the offset keys still have the transform style, which is then reset to 0. I have not been able to solve this problem yet, but I continue to figure it out.
The Bad: However, now the items themselves very briefly flash on rearrange. Sometimes multiple items, not just the ones being dragged. To me this suggests that the draggable flatlist is being re-rendered.
@kristof-kovacs I just noticed the same when in onDragEnd I updated my state with exactly the data I got from the library, but if I do data.map(item => ({ ...item })) the flash goes away. No explanation why, it just works for me :)
@kristof-kovacs I just noticed the same when in
onDragEndI updated my state with exactly thedataI got from the library, but if I dodata.map(item => ({ ...item }))the flash goes away. No explanation why, it just works for me :)
It didn't help me ((
@ddrozdov this actually helped for me as well for one moment, but then it reverted to the same behavior. So unfortunately not this did not fix it.
However, I still am running into the issue of some of the items that I move are resized wrong and do not size down after drag
I also have the same problem. Even in the example, empty app. Should I try downgrading the Expo version?
Bumping this thread to see if anybody has been able to find a solution, or perhaps an alternative package. I saw @harveyappleton was working on a fork for example.
@kristof-kovacs I found this library https://github.com/omahili/react-native-reorderable-list. It worked nicely for me, without any glitches
For me what worked was installing this PR: https://github.com/computerjazz/react-native-draggable-flatlist/pull/551, Doing this comment: https://github.com/computerjazz/react-native-draggable-flatlist/issues/561#issuecomment-2545878644, And applied this patch: https://github.com/computerjazz/react-native-draggable-flatlist/issues/561#issuecomment-2511831441
Maybe one or all of those did the trick.
@ddrozdov provided a patch that worked on my recent React Native project (without expo). However it doesn't work for me in other projects using Expo SDK 52.0 anymore.
@Alex1899 that looks like a great alternative actually! Unfortunately it does not support horizontal scrolling, which is what or project requires.
I have similar glitches in the same situation on sdk 52 with the new architecture enabled. When I disable the new architecture it works much better but still I get the same messages as @fonodi :
Also I'm seeing a lot of console errors during the dragging.
(NOBRIDGE) WARN [Reanimated] Tried to modify key `current` of an object which has been already passed to a worklet. See https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#tried-to-modify-key-of-an-object-which-has-been-converted-to-a-shareable for more details.
Getting this issue on Expo 52,
Managed to fix the same issue in my project with this patch, please check if it helps. react-native-draggable-flatlist+4.0.1.patch.txt
I applied your patch, now It's not so horrible, but I still can see some glitches...
Thx for a patch works like a charm 🚀