Search code examples
javascriptreactjsfrontendcomponentsstate

I cannot update state, because DND kit in react


I have an issue using the deleteProyect function, when the client clicks the button, the component does not eliminate the object in the array unless yo click as fast as you can, so it could be something related to useEfect IDK, i hope you can help me, thanks!

ProyectContext.jsx

import React, { useState, createContext, useEffect } from "react";
import { proyects as data } from "../data/proyects";

export const ProyectContext = createContext({});
export function ProyectContextProvider(props) {
  const [proyects, setProyects] = useState([]);

  useEffect(() => {
    setProyects(data);
  }, []);

  function createProyect(title, platform) {
    setProyects((prevProyects) => [
      ...prevProyects,
      {
        id: prevProyects.length,
        title: title,
        platform: platform,
        img: "https://www.lacorformacion.com/wp-content/uploads/curso-por-defecto.jpg",
      },
    ]);
  }

  
  function deleteProyect(proyectID) {
    setProyects((prevProyects) => {
      const updatedProyects = prevProyects.filter((proyect) => proyect.id !== proyectID);
      return updatedProyects;
    });
  }


  return (
    <ProyectContext.Provider
      value={{ proyects, setProyects, createProyect, deleteProyect }}
    >
      {props.children}
    </ProyectContext.Provider>
  );
}

ProyectList.jsx

import React, { useContext, useEffect } from "react";
import { ProyectContext } from "../../context/ProyectContext";
import { DndContext, closestCenter } from "@dnd-kit/core";
import {
  arrayMove,
  SortableContext,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import ProyectCard from "./ProyectCard";

function ProyectList() {
  const { proyects, setProyects } = useContext(ProyectContext);

  function handleDragEnd(evt) {
    const { active, over } = evt;
    
    setProyects((proyects) => {
      const oldIndex = proyects.findIndex(
        (proyect) => proyect.id === active.id
      );
      const newIndex = proyects.findIndex((proyect) => proyect.id === over.id);

      return arrayMove(proyects, oldIndex, newIndex);
    });
  }
  return (
    <>
      <DndContext collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
        <SortableContext
          strategy={verticalListSortingStrategy}
          items={proyects}
        >
          {proyects.map((proyect) => (
            <ProyectCard key={proyect.title} proyect={proyect} />
          ))}
        </SortableContext>
      </DndContext>
    </>
  );
}

export default ProyectList;

ProyectCard.jsx

import { useContext } from "react";
import { ProyectContext } from "../../context/ProyectContext";
import {
  Card,
  Image,
  Stack,
  CardBody,
  Button,
  Heading,
  Text,
} from "@chakra-ui/react";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";

function ProyectCard({ proyect }) {
  const { deleteProyect } = useContext(ProyectContext);

  const { attributes, listeners, setNodeRef, transform, transition } =
    useSortable({ id: proyect.id });

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

  return (
    <Card
      ref={setNodeRef}
      style={style}
      {...attributes}
      {...listeners}
      direction={{ base: "column", sm: "row" }}
      overflow="hidden"
      variant="outline"
      marginRight={{ base: 0, md: 200 }}
    >
      <Image
        paddingTop={5}
        paddingStart={5}
        objectFit="cover"
        maxH={{ base: "100%", sm: "120px" }}
        maxW={{ base: "100%", sm: "200px" }}
        src={proyect.img}
        alt={proyect.title}
      />

      <Stack>
        <CardBody>
          <Heading size="md">{proyect.title}</Heading>

          <Text py="2">{proyect.platform}</Text>
          <Button variant="solid" colorScheme="blue" marginEnd={4}>
            Planificar
          </Button>
          <Button colorScheme="red" onClick={() => deleteProyect(proyect.id)}>
            Eliminar
          </Button>
        </CardBody>
      </Stack>
    </Card>
  );
}

export default ProyectCard;

i tried using use reducer to manage the complex state, but i could not solve the issue


Solution

  • Your drag listeners are being activated even for the click action, hence the issue. To solve the issue, you can define the DnD in such a way that drag should be listened only if the drag caused atleast a 10 pixel distance movement.

    Inside the ProyectList component

    const sensors = useSensors(
      useSensor(MouseSensor, {
        activationConstraint: {
          distance: 10,
        },
      }),
    );
    <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
    

    useSensors, useSensor, MouseSensor are imported from '@dnd-kit/core'