@souscheflabs/reanimated-flashlist
v0.3.3
Published
A high-performance animated FlashList with drag-to-reorder and entry/exit animations (New Architecture)
Maintainers
Readme
@souscheflabs/reanimated-flashlist
A high-performance animated FlashList with drag-to-reorder and entry/exit animations for React Native.
Features
- Drag-to-reorder with smooth animations and autoscroll
- Entry animations when items appear in the list
- Exit animations with configurable slide/fade/scale effects
- Layout animations for remaining items when one is removed
- 60fps performance via Reanimated UI-thread animations
- Full TypeScript support with generics
Installation
From npm (when published)
npm install @souscheflabs/reanimated-flashlistFrom GitHub (private repo)
Using HTTPS (will prompt for credentials):
npm install github:SousChefLabs/reanimated-flashlist#v0.1.1Using SSH (recommended for CI/private repos):
npm install git+ssh://[email protected]:SousChefLabs/reanimated-flashlist.git#v0.1.1Or add to package.json:
{
"dependencies": {
"@souscheflabs/reanimated-flashlist": "github:SousChefLabs/reanimated-flashlist#v0.1.1"
}
}Replace v0.1.1 with the desired version tag.
Requirements
React Native New Architecture required. This library uses TurboModules and JSI for optimal performance.
- React Native 0.74.0+ with New Architecture enabled
@shopify/flash-listv2.0.0+react-native-reanimatedv4.0.0+react-native-gesture-handlerv2.14.0+
npm install @shopify/flash-list react-native-reanimated react-native-gesture-handlerQuick Start
import { AnimatedFlashList, type AnimatedListItem } from '@souscheflabs/reanimated-flashlist';
import { GestureDetector } from 'react-native-gesture-handler';
interface MyItem extends AnimatedListItem {
title: string;
}
function MyList() {
const [items, setItems] = useState<MyItem[]>([
{ id: '1', title: 'Item 1' },
{ id: '2', title: 'Item 2' },
]);
return (
<AnimatedFlashList<MyItem>
data={items}
keyExtractor={(item) => item.id}
renderItem={({ item, dragHandleProps, triggerExitAnimation }) => (
<View style={styles.item}>
<Text>{item.title}</Text>
{/* Drag handle */}
{dragHandleProps && (
<GestureDetector gesture={dragHandleProps.gesture}>
<View style={styles.dragHandle}>
<DragIcon />
</View>
</GestureDetector>
)}
{/* Delete button with exit animation */}
<TouchableOpacity
onPress={() => {
triggerExitAnimation(1, () => {
setItems(prev => prev.filter(i => i.id !== item.id));
}, 'fast');
}}
>
<DeleteIcon />
</TouchableOpacity>
</View>
)}
dragEnabled
onReorder={(itemId, fromIndex, toIndex) => {
setItems(prev => {
const newItems = [...prev];
const [removed] = newItems.splice(fromIndex, 1);
newItems.splice(toIndex, 0, removed);
return newItems;
});
}}
/>
);
}API Reference
AnimatedFlashListProps
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| data | T[] | Required | Array of items (must extend AnimatedListItem) |
| keyExtractor | (item: T, index: number) => string | Required | Extract unique key for each item |
| renderItem | (info: AnimatedRenderItemInfo<T>) => ReactElement | Required | Render function for items |
| dragEnabled | boolean | false | Enable drag-to-reorder |
| onReorder | (itemId, fromIndex, toIndex) => void | - | Called when item is reordered |
| onReorderByNeighbors | (itemId, afterId, beforeId) => void | - | Alternative callback with neighbor IDs (for fractional indexing) |
| canDrag | (item: T, index: number) => boolean | () => true | Control which items can be dragged |
| onHapticFeedback | (type: HapticFeedbackType) => void | - | Haptic feedback callback |
| config | AnimatedFlashListConfig | - | Configuration overrides |
AnimatedRenderItemInfo
Props passed to your renderItem function:
| Prop | Type | Description |
|------|------|-------------|
| item | T | The item data |
| index | number | Current index |
| totalItems | number | Total items in list |
| dragHandleProps | { gesture, isDragging } \| null | Spread onto GestureDetector for drag handle |
| isDragEnabled | boolean | Whether drag is enabled for this item |
| triggerExitAnimation | (direction, onComplete, preset?) => void | Trigger exit animation |
| resetExitAnimation | () => void | Reset exit animation state |
Recipes
Checkbox Toggle with Exit Animation
When a checkbox is toggled and the item should exit:
renderItem={({ item, triggerExitAnimation }) => (
<View style={styles.item}>
<Checkbox
checked={item.completed}
onToggle={() => {
// Trigger exit animation, then remove item
triggerExitAnimation(1, () => {
removeItem(item.id);
}, 'fast'); // 'fast' preset for quick actions
}}
/>
<Text>{item.title}</Text>
</View>
)}Swipe to Delete
renderItem={({ item, triggerExitAnimation }) => (
<Swipeable
onSwipeRight={() => {
triggerExitAnimation(1, () => deleteItem(item.id));
}}
onSwipeLeft={() => {
triggerExitAnimation(-1, () => deleteItem(item.id));
}}
>
<ItemContent item={item} />
</Swipeable>
)}Custom Drag Handle
renderItem={({ item, dragHandleProps }) => (
<View style={styles.item}>
<Text>{item.title}</Text>
{dragHandleProps && (
<GestureDetector gesture={dragHandleProps.gesture}>
<Animated.View
style={[
styles.dragHandle,
// Optional: visual feedback during drag
useAnimatedStyle(() => ({
opacity: dragHandleProps.isDragging.value ? 0.5 : 1,
})),
]}
>
<GripIcon />
</Animated.View>
</GestureDetector>
)}
</View>
)}Configuration
Drag Configuration
<AnimatedFlashList
config={{
drag: {
itemHeight: 80, // Item height for drag calculations
dragScale: 1.05, // Scale when dragging
longPressDuration: 200, // ms to activate drag
edgeThreshold: 80, // px from edge to trigger autoscroll
maxScrollSpeed: 10, // Autoscroll speed
},
}}
/>Animation Presets
Exit animations have two presets:
'default'(300ms): Standard exit with staggered fade/scale'fast'(200ms): Quick exit for checkbox toggles
// Use fast preset for quick actions
triggerExitAnimation(1, onComplete, 'fast');
// Use default preset for deliberate actions
triggerExitAnimation(-1, onComplete, 'default');Layout Animations
When an item exits the list, remaining items automatically animate to fill the gap. This uses React Native's LayoutAnimation API and is enabled by default.
The animation is triggered automatically when triggerExitAnimation is called - no additional setup required.
Advanced Usage
Using Individual Hooks
For custom implementations, you can use the hooks directly:
import {
useDragGesture,
useDragShift,
useDragAnimatedStyle,
useListExitAnimation,
useListEntryAnimation,
} from '@souscheflabs/reanimated-flashlist';Context Providers
For building custom list implementations:
import {
DragStateProvider,
ListAnimationProvider,
useDragState,
useListAnimation,
} from '@souscheflabs/reanimated-flashlist';License
MIT
