hand Inicio

SERVICIOS

Salir

nochedía

Drag-n-drop con react-beautiful-dnd

800 palabras
3 minutos
July 7, 2020

Hay muchas librerías para hacer drag and drop de elementos de forma más o menos sencilla

Aquí exploro la librería react-beautiful-dnd, posiblemente una de las mejores

Prólogo

Para implementar el movimiento dran-n-drop en un elemento basta con definir qué zonas son contenedores y qué elementos son movibles

Pero eso se dice bastante más rápido de lo que se hace

La librería react-beautiful-dnd, de Atlassian (los compradores de Trello, aquí tienes el artículo donde la presentaron) es una librería que nos facilita esta implementación orientada a una aplicación precisamente como la de Trello

Vale, pues vamos allá

  1. Prólogo
  2. Generando los elementos
  3. Drag and Drop
  4. Reordenando la lista

Generando los elementos

La idea es tener dos columnas con elementos que se puedan mover entre ellas

Bien, pues necesitamos definir esos elementos

Lo hago en un entorno React, si lo quieres probar te recomiendo codesandbox.io

Si utilizas los botones que te pongo en algunos de los códigos recuerda que tienes que añadir las librerías externas pertinentes, de emotion son @emotion/styled y @emotion/core

Importo la librería de React y también el styled de @emotion, que me permitirá definir los estilos a la manera de css-in-js

Defino los componentes css

Y listos, ya sólo me queda la parte de JavaScript

image

Drag and Drop

Parece sencillo, pero no lo es tanto

Si definimos los elementos como hemos hecho arriba, tendremos problemas para reorganizarlos ya que deberíamos acceder al DOM moverlos, actualizarlo, etc etc

Mucho mejor si trabajamos con una estructura de datos, y luego representamos esa estructura en formato html

Bien, pues vamos a hacerlo, y lo hacemos con un useState ya que queremos que esta estructura sea persistente y no se nos reinicialice cada vez que haya un repintado

Perfecto, ahora ya sí que vamos bien

En cada elemento de los arrays de la estructura le defino también un id aparte del text, esto lo hago como requisito de la librería react-beautiful-dnd

Seguimos

Lo primero es definir toda el área donde pasará todo, y lo hacemos con <DragDropContext>

Ahora necesito definir las zonas donde podamos soltar los elementos, lo hago con <Droppable>, y serán las dos columnas

El atributo droppableId tiene que ser único para cada unidad, utilizo el que ya he definido en la estructura de datos

Vamo bien

Pero lo de arriba no funciona

Por qué?

Porque <Droppable> no es un componente "normal" sino que es un Render Prop

Un componente se define así

Y un Render Prop se definen así

Cuando utilizamos un componente lo hacemos así

Y cuando utilizamos un render prop

La utilidad de los render props es que en la función recibimos información que nos es útil, y es el caso que nos ocupa

Pues nada, lo reescribo para que funcione

Los valores que recibo son provided y snapshot, luego los utilizaré

Seguimos, ahora viene el definir los elementos que puedo mover, y los defino con <Draggable>

Y este Draggable es, al igual que antes, un Render Prop así que ya lo añado como toca

Al igual que antes tenemos un atributo draggableId y en este caso su valor también lo referimos al id de la estructura de datos

También aprovecho y añado los key para que React no proteste

Y siguiendo las instrucciones de la librería también añadimos un index para <Draggable> que no puede contener el valor de la key

Y al igual de antes recibo provided y snapshot, luego los utilizaré

Ahora es el momento de utilizar los props que recibimos con el Render Props, siguiendo las directrices de la librería

Como ves se trata de referencias para asignar a los componentes, y de props que volcamos también a los distintos componentes, más el provided.placeholder, un componente que lo ponemos al final de todos los ítems que hemos volcado

Y ya lo tenemos

Aunque eso sí, nos falta definir la función onDragEnd

Reordenando la lista

Teníamos la función onDragEnd que se ejecutaba cuando dejábamos un elemento que habíamos arrastrado previamente

Esa función recibe el argumento result, y lo primero que haremos será retornar el valor (es decir, no hacer nada) si no hay destinación (se ha soltado el elemento fuera de la zona pertinente), o si la destinación es la misma que el origen (con lo que no tenemos que reordenar nada)

Si no es ninguna de estos dos casos, lo que tenemos que hacer es reordenar la lista (la estructura de datos del principio)

Una vez esté reordenada, React ya nos repintará el render y veremos cómo la lista se reordena como le corresponde

Para reordenar la lista tenemos los índices que ya los hemos definido en la estructura con los id

Los nuevos índices nos vienen con result y el índice de inicio result.source.index y de destinación result.destination.index

Bien, pues ahora basta con quitar el elemento concreto e insertarlo a donde toca, lo hacemos con splice, y encontramos los elementos que tocan con findIndex

Mejor si lo encapsulamos en una función aparte, y mejor si en lugar de cambiar la lista generamos una lista nueva

Si evitamos modificar variables (principio de inmutabilidad) nos ahorramos toda una serie de bugs típicos que ocurren cuando modificamos variables

Respetar ese principio es uno de los pilares de la programación funcional

Y ya lo tenemos

Puedes ver el código completo aquí, donde le he cambiado el nombre del componente para que también puedas verlo en codesandbox (recuerda que tienes que añadirle las librerías pertinentes)

image

🙋‍♂️

Qué tal el curso?
👌 Bien 🙌🙌
👍 Bien, pero algunas cosas podrían explicarse mejor 😬
🤷‍♂️ Da por sentadas demasiadas cosas 😒
🤷‍♂️ A ver, hay poca chicha 😬
🤷‍♂️ Los ejemplos no son muy claros 🙇‍♂️
🤷‍♂️ No se entiende, está mal escrito 👎
✍️ Hay errores, revísalo en cuanto puedas 🙏

Quizá te interese

Privacidad
by kuworking.com
[ 2020 >> kuworking ]