En este tutorial vamos a crear una aplicacion de React que nos permita reordenar elementos de una lista usando un modulo llamado React dnd Kit.
Creacion del Proyecto
Primero crearemos un proyecto usando Vitejs, a traves del siguiente comando:
npm create vite
Con las siguientes configuraciones:
√ Project name: ... react-dnd-kit-tutorial
√ Select a framework: » React
√ Select a variant: » JavaScript
Ahora ejecutemos el proyecto, usando los comandos:
cd react-dnd-kit-tutorial
npm install
npm run dev
Limpiemos el proyecto
Antes de empezar a escribir codigo, primero limpiemos el proyecto de codigo y archivos innecesarios, primero vamos a ir en App.jsx, dejandolo asi:
function App() {
return (
<div>App</div>
)
}
export default App
Luego elimina el archivo App.css
Y en index.css
quita todo el contenido dejando vacio el archivo.
Instalacion de TailwindCSS
Ahora vamos a instalar TailwindCSS, para eso puedes seguir esta guia de la documentación: https://tailwindcss.com/docs/guides/vite
Instalacion de React Dnd Kit
npm i @dnd-kit/core @dnd-kit/utilities @dnd-kit/sortable
en App.jsx, creemos un contexto para los elementos que vamos a arrastrar:
import { DndContext, closestCenter } from "@dnd-kit/core";
import { useState } from "react";
function App() {
const [people, setPeople] = useState([
{ id: 1, name: "John" },
{ id: 2, name: "Sarah" },
{ id: 3, name: "Paul" },
]);
const handleDragEnd = (event) => {
console.log("drag end");
};
return (
<DndContext collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
<h1 className="text-2xl font-bold">Users List</h1>
</DndContext>
);
}
export default App;
SortableContext
Ahora crearemos un componente que sera el contenedor de cada uno de los elementos que queremos arrastrar verticalmente en pantalla, este componente es el SortableContext
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
...
return (
<DndContext collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
<h1 className="text-2xl font-bold">Users List</h1>
<SortableContext
items={people}
strategy={verticalListSortingStrategy}
>
{/* components */}
</SortableContext>
</DndContext>
);
Luego crearemos un componente llamado UserItem.jsx
, que sera un solo elemento que muestre un usuario:
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
function User({ user }) {
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id: user.id });
const style = {
transform: CSS.Transform.toString(transform),
transition,
};
return (
<div
style={style}
ref={setNodeRef}
{...attributes}
{...listeners}
className="bg-white p-4 rounded-md shadow-md"
>
<h1>{user.name}</h1>
</div>
);
}
export default User;
En este componente usamos el hook de dnd-kit llamado useSortable que nos da unas propiedades que simplemente tenemos que pasar al contenedor del componente para que este pueda ser arrastrado.
Luego crearemos una lista de estos usuarios en el contendor en App.jsx
<DndContext
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<h1 className="text-2xl font-bold">Users List</h1>
<SortableContext
items={people}
strategy={verticalListSortingStrategy}
>
{people.map((user) => (
<User key={user.id} user={user} />
))}
</SortableContext>
</DndContext>
tambien añadiremos unos estilos para que apareza centrado la lista:
return (
<div className="flex justify-center items-center">
<div className="w-4/6">
<DndContext
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<h1 className="text-2xl font-bold">Users List</h1>
<SortableContext
items={people}
strategy={verticalListSortingStrategy}
>
{people.map((user) => (
<User key={user.id} user={user} />
))}
</SortableContext>
</DndContext>
</div>
</div>
);
Ahora ya puedes arrastrar los elementos pero estos aun no se mantienen en la posicion en que lo estas colocando. Esto es porque el estado noe esta cambiando, asi que en cada arrastrada de elemento, cuando acabe el estado debe actualizarse, esto lo puedes hacer en la funcion handleDragEnd
:
import {
...
arrayMove,
} from "@dnd-kit/sortable";
const handleDragEnd = (event) => {
const { active, over } = event;
console.log("active", active.id);
console.log("over", over.id);
if (!active.id !== over.id) {
setPeople((people) => {
const oldIndex = people.findIndex((person) => person.id === active.id);
const newIndex = people.findIndex((person) => person.id === over.id);
console.log(arrayMove(people, oldIndex, newIndex));
return arrayMove(people, oldIndex, newIndex);
});
}
console.log("drag end");
};
Listo cone esto ya tienes ordenado el arreglo y ahora solo tienes que guardar ese arreglo quizas enviandolo a una API o en el localstorageo o donde lo necesites.
Más Recursos
Otras Bibliotecas Similares
Esta biblioteca tambien puedes usarla en reemplazo de bibliotecas como React Beautiful Dnd que ya no le estan dando mantenimiento: