1.4.8 • Published 10 months ago

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

Weekly downloads
-
License
MIT
Repository
github
Last release
10 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

10 months ago

1.4.4

10 months ago

1.4.8

10 months ago

1.4.7

10 months ago

1.4.2

10 months ago

1.4.1

10 months ago

1.2.9

10 months ago

1.2.8

10 months ago

1.2.7

10 months ago

1.2.6

10 months ago

1.2.5

10 months ago

1.2.4

10 months ago

1.2.1

10 months ago

1.2.0

10 months ago

1.1.0

10 months ago

1.0.1

10 months ago

1.0.0

10 months ago