1.4.8 • Published 9 months ago

react-native-drag-n-drop-everywhere v1.4.8

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

react-native-drag-n-drop-everywhere

A scrollable React Native drag-and-drop library that doesn't use FlatList, which can sometimes cause re-render issues. Designed to work on Web, iOS, and Android.
Built with react-native-reanimated and react-native-gesture-handler. Supports custom item rendering, grips for drag initiation, and more.

Web PreviewiOS PreviewAndroid Preview

Live Demo

Installation

npm install react-native-drag-n-drop-everywhere

Ensure you have installed and configured the following:

  • react-native-reanimated
  • react-native-gesture-handler
  • (Optional) For haptic feedback on iOS: expo-haptics

For setup instructions, refer to their documentation:

Usage

import { Platform, Text, View } from 'react-native';
import DragList from 'react-native-drag-n-drop-everywhere';
import { runOnJS } from 'react-native-reanimated';
import * as Haptics from 'expo-haptics';

const MyDragList = () => {
  const dataIDsArray = [
    "95a6885b-64ab-468c-9334-62c4095df459",
    "b592f039-b4d6-420a-b731-0964172ed142",
    "dba923d8-6743-47ab-8923-8e45eacdb204",
  ];

  const data = {
    "95a6885b-64ab-468c-9334-62c4095df459": 
      { title: 'Entertainment', type: "CATEGORY_TYPE_EXPENSES" },
    "b592f039-b4d6-420a-b731-0964172ed142": 
      { title: 'Groceries', type: "CATEGORY_TYPE_EXPENSES" },
    "dba923d8-6743-47ab-8923-8e45eacdb204": 
      { title: 'Sport', type: "CATEGORY_TYPE_EXPENSES" },
  };

  const renderItem = ({ item }) => (
    <View style={{ paddingHorizontal: 20 }}>
      <Text>{data[item].title}</Text>
      <Text>{data[item].type}</Text>
    </View>
  );

  const renderGrip = () => (
      <Text style={{ fontSize: 30, lineHeight: 30, fontWeight: "600" }}>:::</Text>
  );

  const onUpdateCallback = (newSortedData) => {
    // Do not change dataIDsArray directly in useState. It will cause two-way binding and extra re-renders. 
    // Instead, dispatch this value
    console.log(newSortedData);
  };

  return (
    <DragList
      dataIDs={dataIDsArray}                  // Array of IDs, required
      renderItem={renderItem}                 // Required
      callbackNewDataIds={onUpdateCallback}   // Required, callback for sorted result (dataIDs)
      renderGrip={renderGrip}

      style={{ paddingTop: 100 }}
      contentContainerStyle={{ paddingHorizontal: 10 }}
      itemContainerStyle={{ borderWidth: 2 }}

      itemsGap={10}
      itemHeight={60}
      itemBorderRadius={8}
      backgroundOnHold={"#f0f0f0"}
      passVibration={() => {
        if (Platform.OS === 'ios') {
          runOnJS(Haptics.impactAsync)(
            Haptics.ImpactFeedbackStyle.Medium
          );
        }
      }}
    />
  );
};

Preventing Extra Re-renders (Optional)

If you're using global state (e.g., Redux) to store arrayIDs and update them in callbackNewDataIds, and you want to prevent extra re-renders of your DragList component, use this approach in the parent component:

import { useStore } from 'react-redux';
import { useState } from 'react';
import { useFocusEffect } from '@react-navigation/native'

const ParentComponent = () => {
  const store = useStore();
  const [items, setItems] = useState(null);

  useFocusEffect(() => { // or, useEffect if you don't want to focus it onGoback / etc
    const state = store.getState();
    const itemsIDs = state.categories.itemsIds; // your itemsIds in state
    setItems(itemsIDs.slice()); // slice to avoid direct reference
  });

  if (!items) return null;

  return (
    // Your parent component JSX
  );
};

Props

PropTypeDefaultRequiredDescription
dataIDsArray[]YesAn array of unique identifiers corresponding to each list item.
renderItemFunction-YesFunction to render each list item. Receives { item } as its first argument.
callbackNewDataIdsFunction-YesCallback that receives changes (sorted array of dataIDs). Note: do not change the provided dataIDs array directly in state, as it will cause two-way binding and extra re-renders.
renderGripFunctionnullNoOptional function to render a grip for dragging.
itemsGapNumber5NoThe space (in pixels) between each list item.
itemHeightNumber50NoThe height (in pixels) of each item.
styleObject{}NoCustom styles for the ScrollView.
contentContainerStyleObject{}NoCustom styles for the content container of the ScrollView.
itemContainerStyleObject{}NoCustom styles for the container of each individual item.
itemBorderRadiusNumber10NoThe border radius of each draggable item.
backgroundOnHoldString#e3e3e3NoThe background color of an item while it's being dragged.
passVibrationFunctionnullNoFunction to trigger haptic feedback when an item starts moving.

Notes

  • dataIDs: Should be an array of unique identifiers (strings) that correspond to each list item.
  • keyExtractor: A function that extracts the key from each item in the data. Commonly, this will be the item's ID.
  • renderGrip: Customize the drag handle or "grip" for each item. Defaults to a Text grip if not provided.
  • passVibration: For iOS, you can use Expo Haptics to trigger haptic feedback when the drag starts.

License

MIT


1.4.6

9 months ago

1.4.4

9 months ago

1.4.8

9 months ago

1.4.7

9 months ago

1.4.2

9 months ago

1.4.1

9 months ago

1.2.9

9 months ago

1.2.8

9 months ago

1.2.7

9 months ago

1.2.6

9 months ago

1.2.5

9 months ago

1.2.4

9 months ago

1.2.1

9 months ago

1.2.0

9 months ago

1.1.0

9 months ago

1.0.1

9 months ago

1.0.0

9 months ago