react-native-draggable-flatlist

repository·main·Indexed 24 days ago

https://github.com/computerjazz/react-native-draggable-flatlist

A drag-and-drop-enabled FlatList component for React Native (v4.0.3) powered by Reanimated and React Native Gesture Handler. It provides specialized props for drag-and-drop functionality, built-in cell decorators (ScaleDecorator, ShadowDecorator, OpacityDecorator) for hover animations, and support for nested lists via NestableScrollContainer and NestableDraggableFlatList.

Tokens
6.3K
Snippets
8
Records
20
Agent score
79%

What's inside react-native-draggable-flatlist

  1. Use Cell Decorators for hover animations

    main

    Cell Decorators provide a simple way to add common animations to your list items when they become active (hovered/dragged).

    Available built-in decorators:

    • ScaleDecorator: Scales up the active item.
    • ShadowDecorator: Adds a shadow to the active item.
    • OpacityDecorator: Changes the opacity of the active item.

    You can wrap your renderItem component with these decorators. For custom animations, you can use the useOnCellActiveAnimation hook.

  2. Install react-native-draggable-flatlist

    main

    To use react-native-draggable-flatlist, you must first install its peer dependencies, react-native-reanimated and react-native-gesture-handler. Note that react-native-gesture-handler may require manual changes to MainActivity.java on Android.

    After setting up the peer dependencies, install the package using npm or yarn:

  3. Nest multiple DraggableFlatLists

    main

    To render multiple DraggableFlatList components within a single scrollable parent, use NestableScrollContainer and NestableDraggableFlatList.

    NestableScrollContainer extends react-native-gesture-handler's ScrollView, and NestableDraggableFlatList extends DraggableFlatList. This setup allows multiple lists to coexist in a single scrollable area without conflicting gestures. Note that React Native warnings regarding nested list performance are automatically disabled in this configuration.

    import { NestableScrollContainer, NestableDraggableFlatList } from "react-native-draggable-flatlist"
    
    ...
    
      const [data1, setData1] = useState(initialData1);
      const [data2, setData2] = useState(initialData2);
      const [data3, setData3] = useState(initialData3);
    
      return (
        <NestableScrollContainer>
          <Header text='List 1' />
          <NestableDraggableFlatList
            data={data1}
            renderItem={renderItem}
            keyExtractor={keyExtractor}
            onDragEnd={({ data }) => setData1(data)}
          />
          <Header text='List 2' />
          <NestableDraggableFlatList
            data={data2}
            renderItem={renderItem}
            keyExtractor={keyExtractor}
            onDragEnd={({ data }) => setData2(data)}
          />
          <Header text='List 3' />
          <NestableDraggableFlatList
            data={data3}
            renderItem={renderItem}
            keyExtractor={keyExtractor}
            onDragEnd={({ data }) => setData3(data)}
          />
        </NestableScrollContainer>
      )
  4. Use ScaleDecorator to enhance drag feedback

    main

    The ScaleDecorator is a component provided by react-native-draggable-flatlist that can be wrapped around your rendered items. It provides visual feedback (scaling) when an item is being actively dragged, helping the user understand which item is currently being manipulated.

    import DraggableFlatList, {
      ScaleDecorator,
    } from "react-native-draggable-flatlist";
    
    // Inside renderItem:
    const renderItem = ({ item, drag, isActive }: RenderItemParams<Item>) => {
      return (
        <ScaleDecorator>
          <TouchableOpacity onLongPress={drag}>
            <Text>{item.label}</Text>
          </TouchableOpacity>
        </ScaleDecorator>
      );
    };
  5. Implement a basic DraggableFlatList

    main

    To use DraggableFlatList, you must provide a data array, a keyExtractor function, and a renderItem function. The renderItem function receives an object containing item, drag, and isActive. To enable dragging, you should call the drag function (typically via an onLongPress handler) on the component you want to act as the drag handle. Use the onDragEnd prop to update your local state with the new data order after a drag operation completes.

    import React, { useState } from "react";
    import { Text, View, StyleSheet, TouchableOpacity } from "react-native";
    import DraggableFlatList, {
      ScaleDecorator,
    } from "react-native-draggable-flatlist";
    
    // ... (data setup) ...
    
    export default function App() {
      const [data, setData] = useState(initialData);
    
      const renderItem = ({ item, drag, isActive }: RenderItemParams<Item>) => {
        return (
          <ScaleDecorator>
            <TouchableOpacity
              onLongPress={drag}
              disabled={isActive}
              style=[
                styles.rowItem,
                { backgroundColor: isActive ? "red" : item.backgroundColor },
              ]}
            >
              <Text style={styles.text}>{item.label}</Text>
            </TouchableOpacity>
          </ScaleDecorator>
        );
      };
    
      return (
        <DraggableFlatList
          data={data}
          onDragEnd={({ data }) => setData(data)}
          keyExtractor={(item) => item.key}
          renderItem={renderItem}
        />
      );
    }
  6. Use DraggableFlatList props

    main

    The DraggableFlatList component accepts all standard props from the React Native FlatList, plus several specialized props for drag-and-drop functionality.

    Key props include:

    • data: The array of items to render.
    • renderItem: A function that returns a JSX element. It receives an object containing item, getIndex, drag, and isActive. You must call drag() (e.g., inside an onLongPress) to initiate the dragging state.
    • keyExtractor: A required function to provide a unique key for each item.
    • onDragEnd: A callback triggered after the drag animation completes, providing the updated data, the from index, and the to index.
    • renderPlaceholder: A component to render in the space occupied by the item being hovered over.
    • activationDistance: Useful for preventing accidental drags when the list is inside a TabNavigator or ScrollView.
  7. Reference: DraggableFlatList Props

    main

    The following table lists the specialized props available for DraggableFlatList.

    | Name                       | Type                                                                                                                     |
    | :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------|
    | `data`                     | `T[]`                                                                                                                                  |
    | `ref`                      | `React.RefObject<FlatList<T>>`                                                                                                         |
    | `renderItem`               | `(params: { item: T, getIndex: () => number \| undefined, drag: () => void, isActive: boolean}) => JSX.Element`                      |
    | `renderPlaceholder`        | `(params: { item: T, index: number }) => React.ReactNode`                                                                               |
    | `keyExtractor`             | `(item: T, index: number) => string`                                                                                                   |
    | `onDragBegin`              | `(index: number) => void`                                                                                                              |
    | `onRelease`                | `(index: number) => void`                                                                                                              |
    | `onDragEnd`                | `(params: { data: T[], from: number, to: number }) => void`                                                                          |
    | `autoscrollThreshold`      | `number`                                                                                                                               |
    | `autoscrollSpeed`          | `number`                                                                                                                               |
    | `animationConfig`          | `Partial<WithSpringConfig>`                                                                                                             |
    | `activationDistance`       | `number`                                                                                                                               |
    | `onScrollOffsetChange`     | `(offset: number) => void`                                                                                                             |
    | `onPlaceholderIndexChange` | `(index: number) => void`                                                                                                               |
    | `dragItemOverflow`         | `boolean`                                                                                                                              |
    | `dragHitSlop`              | `object: {top: number, left: number, bottom: number, right: number}`                                                                  |
    | `debug`                    | `boolean`                                                                                                                              |
    | `containerStyle`           | `StyleProp<ViewStyle>`                                                                                                                  |
    | `simultaneousHandlers`     | `React.Ref<any>` or `React.Ref<any>[]`                                                                                                 |
    | `itemEnteringAnimation`    | Reanimated `AnimationBuilder`                                                                                                           |
    | `itemExitingAnimation`     | Reanimated `AnimationBuilder`                                                                                                           |
    | `itemLayoutAnimation`      | Reanimated `AnimationBuilder`                                                                                                           |
    | `enableLayoutAnimationExperimental`| `boolean`|                                                                                                                                  |
  8. Implement the renderItem function

    main

    The renderItem function is required for DraggableFlatList. It provides the necessary tools to trigger a drag gesture and to style the item based on its active state.

    Parameters (RenderItemParams<T>):

    • item: The data item for the current row.
    • getIndex: A function that returns the current index of the item. Note: This is the "last known index" and may not trigger a re-render immediately upon index change.
    • drag: A function that, when called (e.g., via a press or long press), initiates the drag sequence for this item.
    • isActive: A boolean indicating if the item is currently being dragged.
    type RenderItemParams<T> = {
      item: T;
      getIndex: () => number | undefined;
      drag: () => void;
      isActive: boolean;
    };
    
    export type RenderItem<T> = (params: RenderItemParams<T>) => React.ReactNode;
  9. Implement a custom renderPlaceholder

    main

    The renderPlaceholder prop allows you to define a component that occupies the space where an item is being moved to. This helps maintain list stability and visual continuity during the drag.

    Parameters (RenderPlaceholder<T>):

    • item: The item that is being moved (the placeholder represents its target position).
    • index: The index of the placeholder.
    export type RenderPlaceholder<T> = (params: {
      item: T;
      index: number;
    }) => JSX.Element;
  10. Handle drag end events with DragEndParams

    main

    When a drag operation finishes, the onDragEnd prop provides a DragEndParams<T> object. This is used to update your local state with the new order of items.

    DragEndParams<T> fields:

    • data: The new array of items in their updated order.
    • from: The index where the drag started.
    • to: The index where the drag ended.
    type DragEndParams<T> = {
      data: T[];
      from: number;
      to: number;
    };