React Native Sortables

website·Indexed 29 days ago

https://react-native-sortables-docs.vercel.app

A library for creating sortable layouts in React Native, featuring Sortable Grid and Sortable Flex components. It includes support for custom handles, drop indicators, active item portals, and layout animations, with integration for Reanimated Shared Values.

Tokens
18.6K
Snippets
66
Records
99
Agent score
74%

What's inside React Native Sortables

  1. Overview of React Native Sortables

    React Native Sortables is a library providing smooth drag-and-drop reordering of items via intuitive gesture-based components. It is compatible with both iOS and Android, supports both the New and Old React Native Architectures, and is compatible with Expo. The library is built upon react-native-reanimated and react-native-gesture-handler.
  2. Introduction to the Sortable Flex component

    The Sortable Flex component provides a flex container that allows items to be reordered via drag-and-drop interactions. It is designed for complex flexbox layouts and is more advanced than the Sortable Grid component. Due to the complexity of its layout calculations, it is recommended to use the Sortable Grid component for most standard use cases unless a complex flex layout is specifically required.
  3. Troubleshoot SortableGrid animation choppiness

    If you experience choppy animations while using the auto-scroll feature in development mode on the New Architecture, note that this is a known behavior caused by react-native-reanimated. Performance is smooth on the Old Architecture and in production release builds.
  4. Configure optional haptic feedback for react-native-sortables

    Haptic feedback is optional. The library automatically detects and uses the first available haptics package it finds in the following priority order:

    1. react-native-pulsar: Provides rich haptic presets; requires the New Architecture.
    2. expo-haptics: Recommended for Expo applications.
    3. react-native-haptic-feedback: Recommended for bare React Native workflows.
  5. Optimize Callbacks with Worklets

    For better performance and to avoid thread-jumping overhead, use worklet functions for callbacks. Worklets run directly on the UI thread. To define a worklet, add the 'worklet' directive at the start of the function body. Plain JS functions are supported but run on the JS thread via runOnJS and are less performant.
    const onDragStart = useCallback((params: DragStartParams) => {
      'worklet';
      // This runs on the UI thread
    }, []);
  6. Enable the default drop indicator in Sortable.Flex

    The drop indicator is a visual guide that shows the position where an item will be placed when released. To enable the default drop indicator in a Sortable.Flex component, use the showDropIndicator prop.
    import Sortable from 'react-native-sortables';
    
    <Sortable.Flex
      gap={10}
      showDropIndicator
    >
      {/* items */}
    </Sortable.Flex>
  7. Use Sortable.Touchable for interactive elements in sortable items

    The Sortable.Touchable component is used to add interactive elements (like buttons or links) inside sortable items. It is specifically designed to handle touch gestures (tap, double tap, long press) without conflicting with the drag-and-drop gesture detector used for item activation and movement.
    import Sortable from 'react-native-sortables';
    
    <Sortable.Touchable
      onTap={() => {
        console.log('tapped');
      }}
      onLongPress={() => {
        console.log('long pressed');
      }}
      onTouchesDown={() => {
        console.log('touch started');
      }}
    >
      {/* Your interactive content here */}
    </Sortable.Touchable>
  8. Access sortable item state with useItemContext

    The useItemContext hook provides access to item-related values and drag states. It must be called within a component that is rendered as part of a sortable item. The hook returns an object containing the item's key, its active status, animation progress, and the gesture object required for custom drag handles.
    import { useItemContext } from 'react-native-sortables';
    
    const ctx = useItemContext(); // Must be used inside a sortable item component
  9. Manage zIndex for dragged items with Sortable.Layer

    The Sortable.Layer component automatically manages zIndex values to ensure that items being dragged in a sortable list or grid remain visible above other components on the screen. It detects when a child item starts being dragged and adjusts the visual hierarchy accordingly. If multiple Sortable.Layer components are nested, the drag information bubbles up to update the zIndex in each layer.

    Most sortable components use Sortable.Layer internally, so it should only be used explicitly if you notice dragged items appearing underneath other UI elements.

    import Sortable from 'react-native-sortables';
    
    <Sortable.Layer>
      {/* Other components */}
      <Sortable.Grid 
        // sortable grid props
      />
      {/* Other components */}
    </Sortable.Layer>
  10. Implement a custom drop indicator component

    For advanced visual behavior or animations, you can replace the default indicator with a custom component using the DropIndicatorComponent prop. The custom component receives DropIndicatorComponentProps, which includes animation progress, the active item key, the current drop index, and the ordered list of item keys.
    import type { DropIndicatorComponentProps } from 'react-native-sortables';
    import Animated from 'react-native-reanimated';
    
    function CustomDropIndicator({
      activeAnimationProgress,
      activeItemKey,
      dropIndex,
      orderedItemKeys,
      style
    }: DropIndicatorComponentProps) {
      // Use Reanimated hooks (useDerivedValue, useAnimatedStyle, etc.) 
      // to create custom animations based on the props
      return (
        <Animated.View style={[style, { backgroundColor: 'red' }]} />
      );
    }
    
    export default function App() {
      return (
        <Sortable.Grid
          showDropIndicator
          DropIndicatorComponent={CustomDropIndicator}
          {...otherProps}
        />
      );
    }
  11. Handle press events inside sortable items using Sortable.Touchable

    Use the Sortable.Touchable component when you need to detect press events (like button clicks) on elements nested inside a sortable item. This is specifically useful for components located within the area that detects drag gestures (either the entire item or a Sortable.Handle). Using Sortable.Touchable ensures that a press event is triggered only when the user intends to tap, and not when the item is being dragged.
    import { useState } from 'react';
    import { StyleSheet, Text, View } from 'react-native';
    import Sortable from 'react-native-sortables';
    
    const INITIAL_DATA = ['Poland', 'Germany', 'France'];
    
    export default function FlexTouchableExample() {
      const [data, setData] = useState(INITIAL_DATA);
    
      return (
        <View style={styles.container}>
          <Sortable.Flex
            gap={10}
            onDragEnd={({ order }) => setData(order(data))}>
            {data.map(item => (
              <View key={item} style={styles.card}>
                <Text style={styles.text}>{item}</Text>
                {/* Use Sortable.Touchable for buttons inside the draggable area */}
                <Sortable.Touchable
                  style={styles.deleteButton}
                  onTap={() => setData(prev => prev.filter(i => i !== item))}>
                  <Text style={styles.text}>✕</Text>
                </Sortable.Touchable>
              </View>
            ))}
          </Sortable.Flex>
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      card: {
        flexDirection: 'row',
        paddingHorizontal: 16,
        paddingVertical: 12,
        backgroundColor: 'blue',
        borderRadius: 9999,
        gap: 10,
        alignItems: 'center'
      },
      deleteButton: {
        width: 22,
        height: 22,
        borderRadius: 9999,
        backgroundColor: 'rgba(255, 255, 255, 0.3)',
        justifyContent: 'center',
        alignItems: 'center'
      },
      container: { flex: 1, padding: 10 },
      text: { color: 'white', fontWeight: 'bold' }
    });