Cómo implementar Arrastrar y Soltar con React-Beautiful-DnD
Una vez instalado, vamos al fichero App.js, donde empezamos a construir nuestra app.
¡Vayamos al código!
import React, { useState } from "react";
import { DragDropContext } from "react-beautiful-dnd";
import Column from "./components/Column";
import { status } from "./constants/mock";
const onDragEnd = (result, columns, setColumns) => {
// Implementaremos esta función más adelante
};
function App() {
const [columns, setColumns] = useState(status);
return (
<div style={{ display: "flex", justifyContent: "center", height: "100%" }}>
<DragDropContext
onDragEnd={(result) => onDragEnd(result, columns, setColumns)}
>
{Object.entries(columns).map(([columnId, column], index) => {
return (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center"
}}
key={columnId}
>
<h2>{column.name}</h2>
<div style={{ margin: 8 }}>
<Column
droppableId={columnId}
key={columnId}
index={index}
column={column}
/>
</div>
</div>
);
})}
</DragDropContext>
</div>
);
}
export default App;En el primer fragmento de código se puede apreciar que solo importamos el DragDropContext, que es nuestro wrapper y nos permitirá gestionar las funciones de arrastrar y soltar de la app.
Advertisement
React-Beautiful-DnD
Permite un solo context, pero se pueden hacer implementaciones combinadas
Al definirle un tipo al Droppable, puedes condicionar las funciones del context según ese tipo. Esto permite crear implementaciones más complejas y versátiles.
Además, importamos un juego de datos para simular un funcionamiento real, y también un componente Column, que veremos a continuación.
import React, { memo } from "react";
import PropTypes from "prop-types";
import { Droppable } from "react-beautiful-dnd";
import TaskCard from "./TaskCard";
const Column = ({ droppableId, column }) => {
return (
<Droppable droppableId={droppableId} key={droppableId}>
{(provided, snapshot) => {
return (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={{
background: snapshot.isDraggingOver ? "lightblue" : column.color,
padding: 4,
width: 250,
minHeight: 500,
border: "2px dashed #ccc",
borderRadius: "4px"
}}
>
{column?.items?.map((item, index) => {
return <TaskCard key={item.id} item={item} index={index} />;
})}
{provided.placeholder}
</div>
);
}}
</Droppable>
);
};
Column.propTypes = {
column: PropTypes.object,
droppableId: PropTypes.string
};
export default memo(Column);Lo más relevante de este componente es la importación de Droppable y del uso de la prop droppableId, ya que es la que especificará a React-Beautiful-DnD qué o cuáles serán sus Droppables (columnas).
Por último, importamos el componente hijo TaskCard, que veremos a continuación, y, por supuesto, le pasaremos las props necesarias.
Componente TaskCard
import React, { memo } from "react";
import PropTypes from "prop-types";
import { Draggable } from "react-beautiful-dnd";
import "../styles.css";
function TaskCard({ item, index }) {
return (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided, snapshot) => {
return (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{
userSelect: "none",
padding: 16,
margin: "0 0 8px 0",
minHeight: "50px",
backgroundColor: snapshot.isDragging ? "#263B4A" : "#456C86",
color: "white",
borderRadius: "4px",
...provided.draggableProps.style
}}
>
<div className="conten-card">
<img
src="https://react-beautiful-dnd.netlify.app/static/media/bmo-min.9c65ecdf.png"
alt="logo"
className="logo"
/>
{item.content}
</div>
</div>
);
}}
</Draggable>
);
}
TaskCard.propTypes = {
index: PropTypes.number,
item: PropTypes.object
};
export default memo(TaskCard);Al igual que en el paso anterior, hay determinados puntos relevantes en este componente, como Draggable, tercer pilar de la librería que estamos usando y que nos permitirá arrastrar las tareas entre las distintas columnas, así como otras props que posibilitarán poblar nuestro componente.
Aquí también importamos unos estilos para conformar un poco la app. Muy importante es el uso de {...provided.dragHandleProps}, que hará la magia de mover los elementos.
Estilos CSS
.App {
font-family: sans-serif;
text-align: center;
}
.logo {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 8px;
flex-shrink: 0;
-webkit-box-flex: 0;
flex-grow: 0;
}
.conten-card {
display: flex;
align-items: center;
justify-content: flex-start;
}Advertisement
Implementando la función onDragEnd
Por último, modificamos la función onDragEnd para actualizar el orden de los elementos de cada columna y así terminar nuestra app de ejemplo.
const onDragEnd = (result, columns, setColumns) => {
if (!result.destination) return;
const { source, destination } = result;
if (source.droppableId !== destination.droppableId) {
// Moviendo entre columnas diferentes
const sourceColumn = columns[source.droppableId];
const destColumn = columns[destination.droppableId];
const sourceItems = [...sourceColumn.items];
const destItems = [...destColumn.items];
const [removed] = sourceItems.splice(source.index, 1);
destItems.splice(destination.index, 0, removed);
setColumns({
...columns,
[source.droppableId]: {
...sourceColumn,
items: sourceItems
},
[destination.droppableId]: {
...destColumn,
items: destItems
}
});
} else {
// Moviendo dentro de la misma columna
const column = columns[source.droppableId];
const copiedItems = [...column.items];
const [removed] = copiedItems.splice(source.index, 1);
copiedItems.splice(destination.index, 0, removed);
setColumns({
...columns,
[source.droppableId]: {
...column,
items: copiedItems
}
});
}
};El resultado final es una aplicación funcional que permitirá mover y reasignar múltiples columnas y, a la vez, múltiples elementos en dichas columnas.
Conclusiones
React-Beautiful-DnD es muy versátil por lo que ofrece. La sensación de movimiento natural que tiene el usuario proviene de una serie de características, como la asignación dinámica de espacio para los elementos y la funcionalidad de arrastrar y soltar.
Hay muchos usos posibles de una aplicación de este tipo, desde la creación de organigramas hasta la creación de listas de tareas pendientes y asignaciones de personal, entre otros.
En comparación, React-DnD es más versátil aún, ya que proporciona una abstracción de nivel superior que se puede utilizar para una variedad de listas y movimientos entre listas.
Estos apuntes pueden ser tomados en cuenta a la hora de definir cuál de estas bibliotecas sería más adecuada para su aplicación, ya que ambas tienen puntos fuertes. Si se requiere un enfoque más sólido, es posible que la adecuada sea React-DnD.
Esperamos que este pequeño aporte les sea de utilidad en su proyecto.
Recursos
- Código completo: CodeSandbox - Tutorial Multiple RBD
- Documentación Oficial: GitHub - React-Beautiful-DnD
- Story Book: React-Beautiful-DnD Examples
¿Te ha resultado útil este tutorial? ¡Compártelo con otros desarrolladores que puedan beneficiarse!
Advertisement
Angel LM
Full-stack developer passionate about creating beautiful and functional web applications. Sharing knowledge about React, Next.js, and modern web development.

