clauderic / dnd-kit

The modern, lightweight, performant, accessible and extensible drag & drop toolkit for React.
http://dndkit.com
MIT License
12.89k stars 640 forks source link

Animation not working for Array of objects #183

Closed stevesizer closed 3 years ago

stevesizer commented 3 years ago

Hi,

I have modified your basic example to try and use it with an object array, but doing so stops the animations from happening? Is there any reason for this?

Column.js

import React, { useState, useCallback } from "react";
import { Item } from "./Item";
import {
  DndContext,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import {
  arrayMove,
  SortableContext,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";

export default function Column() {
  const [items, setItems] = useState([
    {
      id: 1,
      name: "Clean Car",
      description: "Take the car to get cleaned",
    },
    {
      id: 2,
      name: "Pick up kids",
      description: "Pick up kids and take them to soccer pratice",
    },
    {
      id: 3,
      name: "Walk Dog",
      description: "Meet up with John and take dog for a walk",
    },
  ]);
  //   const [items, setItems] = useState(["1", "2", "3", "4"]);
  const sensors = useSensors(
    useSensor(PointerSensor),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    })
  );

  return (
    <div className="column">
      <DndContext
        sensors={sensors}
        collisionDetection={closestCenter}
        onDragEnd={handleDragEnd}
      >
        <SortableContext items={items} strategy={verticalListSortingStrategy}>
          {items.map((item) => (
            <Item
              key={item.id}
              id={item.id}
              name={item.name}
              description={item.description}
            />
          ))}
        </SortableContext>
      </DndContext>
    </div>
  );

  function handleDragEnd(event) {
    const { active, over } = event;

    if (active.id !== over.id) {
      console.log(active);
      console.log(items);
      setItems((items) => {
        const oldIndex = items.findIndex((item) => item.id === active.id);
        const newIndex = items.findIndex((item) => item.id === over.id);
        // const oldIndex = items.indexOf(active.id);
        // const newIndex = items.indexOf(over.id);
        return arrayMove(items, oldIndex, newIndex);
      });
    }
  }
}

Item.js

import React from "react";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";

export function Item(props) {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
  } = useSortable({ id: props.id });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
  };

  return (
    <div ref={setNodeRef} style={style} {...attributes} {...listeners}>
      {props.id}
      <p>{props.name}</p>
      <p>{props.description}</p>
    </div>
  );
}
clauderic commented 3 years ago

The <SortableContext> component requires that you pass it the sorted array of the unique identifiers associated to each sortable item via the items prop. This array should look like ["1", "2", "3"], not [{id: "1"}, {id: "2}, {id: "3}].

All you have to do is map your items array to an array of strings that represent the unique identifiers for each item:

export default function Column() {
  const [items, setItems] = useState([
    {
      id: "1",
      name: "Clean Car",
      description: "Take the car to get cleaned",
    },
    {
      id: "2",
      name: "Pick up kids",
      description: "Pick up kids and take them to soccer pratice",
    },
    {
      id: "3",
      name: "Walk Dog",
      description: "Meet up with John and take dog for a walk",
    },
  ]);
  const itemIds = useMemo(() => items.map((item) => item.id), [items]); // ["1", "2", "3"]

  /* ... */

  <SortableContext items={itemIds}>
rockingrohit9639 commented 2 years ago

Hi @clauderic

Does ids like ['6d0900e9', 'de75dce5'] work for this?

enoguchi-lmi commented 2 years ago

Hi @clauderic

Does ids like ['6d0900e9', 'de75dce5'] work for this?

yes

ivanjeremic commented 2 years ago

I have id's like this and it does not work ['1686', '3337', '3225', '3313'] https://codesandbox.io/s/lucid-yalow-77hh97?file=/src/DndWithObjects.tsx

wizardbusiness commented 1 year ago

To save others time who may have missed it in stevesizers code, you also need to replace the indexOf method in handleDragEnd with the findIndex method. This is because indexOf is searching the array for a primitive and will not find it if the elements are objects, whereas you can be more specific about what you're looking for using findIndex's callback

Crovitche-1623 commented 1 year ago

I just came across this same case and found this issue after a few hours of searching. Shouldn't this case be in the documentation (especially the useMemo(...), and the handleDragEnd(event) that need to be modified) ?

albanyacademy commented 6 months ago

edit:nvm not workin