Cómo construir una cuadrícula de arrastrar y soltar con React

Blog

En este tutorial, crearemos una cuadrícula de imágenes de arrastrar y soltar en React. El siguiente gif muestra el efecto deseado:

Este es el título de la imagen

En el momento en que comencé a escribir este artículo, no podía encontrar buenas fuentes de cómo abordar este proyecto y decidí crearlo desde cero por mi cuenta. Además, hay varias bibliotecas excelentes, como reaccionar-hermosa-dnd , pero no ofrecen la sencilla compatibilidad de cuadrícula bidimensional que necesitaba.

El proyecto está disponible en: github.com/tfiechowski/react-dnd-grid-tutorial

Configuración

Comencemos por crear la aplicación e instalar algunas dependencias que usaremos a lo largo del proyecto. react-dnd es la biblioteca que usaremos para las interacciones de arrastrar y soltar, y usaremos styled-components para peinar.

|_+_|

Para construir create-react-app dnd-grid-tutorial cd dnd-grid-tutorial yarn add styled-components react-dnd react-dnd-html5-backend , usaremos React Context. El componente contendrá la información sobre los artículos y también expondrá los métodos para reordenarlos.

Sería posible usar un componente con estado en lugar de Context, pero de esta manera, hay un área mayor de flexibilidad. Si la estructura del componente se volviera un poco más compleja, no requeriría un pase profundo de prop, ya que podemos acceder al contexto básicamente en cualquier lugar, especialmente con GridContext gancho.

comentarios de bots en youtube

Decidamos el enfoque para reordenar los artículos sobre la marcha.

Mecanismo de reordenamiento

Para reordenar los elementos mientras los arrastramos, usaremos un enfoque simple: siempre que el elemento arrastrado esté sobre otro elemento, tomará su lugar y empujará todos los elementos restantes a la derecha un espacio más:

Este es el título de la imagen

Teniendo eso en cuenta y también un requisito de que operemos en los ID de artículo, podemos comenzar a implementar el useContext.

GridContext

Mantendrá la matriz de elementos en su estado y expondrá dos métodos: GridContext y moveItem(sourceId, destinationId).

El setItems(items) función es responsable de mover el elemento de un moveItem dado | en el lugar de otro elemento con sourceId y moviendo el resto un lugar a la derecha. También hay destinationId y move funciones de utilidad para hacer frente a la reorganización de la matriz. moveElement simplemente anula los elementos en el estado de contexto.

los GridContext se puede implementar de la siguiente manera:

|_+_|

src / GridContext.js

DragItem

Ahora, tratemos con el setItems componente e implementarlo así:

|_+_|

src / DragItem.js

Configuración de fuente predeterminada de Chrome

Ahora, conozcamos lo que está sucediendo aquí.

Primero, tenemos el componente en sí envuelto con memorándum . Está mejorando el rendimiento, ya que solo verifica superficialmente si los accesorios cambiaron y, de lo contrario, reutiliza el último resultado renderizado. En los apoyos tenemos:

  • import React, { Component, createContext } from 'react'; import sampleItems from './sampleItems'; // Helper functions function move(array, oldIndex, newIndex) { if (newIndex >= array.length) { newIndex = array.length - 1; } array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]); return array; } function moveElement(array, index, offset) { const newIndex = index + offset; return move(array, index, newIndex); } // Context const GridContext = createContext({ items: [] }); export class GridProvider extends Component { constructor(props) { super(props); this.state = { items: sampleItems, moveItem: this.moveItem, setItems: this.setItems }; } render() { return ( {this.props.children} ); } setItems = items => this.setState({ items }); moveItem = (sourceId, destinationId) => { const sourceIndex = this.state.items.findIndex( item => item.id === sourceId ); const destinationIndex = this.state.items.findIndex( item => item.id === destinationId ); // If source/destination is unknown, do nothing. if (sourceId === -1 || destinationId === -1) { return; } const offset = destinationIndex - sourceIndex; this.setState(state => ({ items: moveElement(state.items, sourceIndex, offset) })); }; } export default GridContext; - ese es el ID único del artículo,
  • DragItem - controlador para mover y reorganizar los elementos,
  • import React, { memo, useRef } from 'react'; import { useDrag, useDrop } from 'react-dnd'; const DragItem = memo(({ id, onMoveItem, children }) => { const ref = useRef(null); const [{ isDragging }, connectDrag] = useDrag({ item: { id, type: 'IMG' }, collect: monitor => { return { isDragging: monitor.isDragging() }; } }); const [, connectDrop] = useDrop({ accept: 'IMG', hover(hoveredOverItem) { if (hoveredOverItem.id !== id) { onMoveItem(hoveredOverItem.id, id); } }); connectDrag(ref); connectDrop(ref); const opacity = isDragging ? 0.5 : 1; const containerStyle = { opacity }; return React.Children.map(children, child => React.cloneElement(child, { forwardedRef: ref, style: containerStyle }) ); }); export default DragItem; - niños para rendir.

Luego creamos un id que se utilizará como referencia al nodo DOM correspondiente.

Arrastrar: La fuente de arrastre se crea con onMoveItem. En el primer elemento de la matriz devuelta, tenemos children. No está disponible de fábrica, pero en realidad es un valor devuelto por ref método justo debajo. El useDrag función tiene acceso a la monitor, que tiene varios métodos auxiliares disponibles . { isDragging } es una propiedad requerida. Ponemos el ID único allí y también un collect para especificar qué tipo de elemento arrastrable es.

Soltar: Ahora configuramos el destino de caída usando collect. item propiedad se establece en type ya que queremos que solo se eliminen aquí los elementos de ese tipo. El useDrop se llama al método cuando un elemento arrastrado se coloca sobre el componente de destino para soltar .

Pregunta: ¿Cómo funciona el accept obtener la función IMG que se está rondando como un argumento?

En nuestro caso, todos los elementos de la cuadrícula se pueden arrastrar y soltar. Los mecanismos de arrastrar y soltar están conectados con el mismo elemento DOM (a través de hover), por lo que cada vez que colocamos el cursor sobre un elemento sobre otro, obtenemos lo que se especificó en ese hover en hoveredOverItem.

Reordenamiento: Al comparar los ID de los elementos arrastrados y suspendidos, podemos detectar el momento en que se deben reordenar los elementos. Lo hacemos de la siguiente forma, utilizando las teclas connectDrag/Drop(ref) manipulador:

|_+_|

Ahora necesitamos conectar nuestro item con el arrastrar y soltar: Lo hacemos llamando a las funciones del conector que obtuvimos de useDrag:

|_+_|

Un poco de estilo: Usemos el onMoveItem variable tenemos que distinguir de alguna manera el elemento que se está arrastrando. Hagámoslo cambiando su opacidad a 0.5:

donde comprar xdai
|_+_|

Representación de niños: Ahora viene una parte un poco complicada. Nos gustaría hover(hoveredOverItem) { if (hoveredOverItem.id !== id) { onMoveItem(hoveredOverItem.id, id); } } para ser lo más reutilizable posible, por lo que no sería razonable poner algunos divs o imágenes directamente aquí. Podemos aprovechar el accesorio de los niños para representar cualquier cosa que pongamos dentro de ref.

Ser capaz de renderizar cualquier cosa dentro de useDrag/Drop es una gran ventaja, pero viene con una advertencia: el connectDrag(ref); connectDrop(ref); que creamos no se puede adjuntar directamente a ningún nodo DOM real aquí y no podemos transmitirlo fácilmente. De acuerdo con la Reaccionar documentación , Eso es porque isDragging no es un apoyo. Al igual que const opacity = isDragging ? 0.5 : 1; const containerStyle = { opacity }; , React lo maneja de manera diferente.

pregunta de entrevista de promesa de javascript

Tendremos que pasarlo como un accesorio personalizado y adjuntarlo manualmente en el componente de destino. Ahora puedes ver la razón detrás de la magia con DragItem y DragItem en el DragItem componente que creamos anteriormente:

|_+_|

ref es solo un div (creado con ref), por lo que pasar key aquí está perfectamente bien. Teniendo eso en cuenta, terminemos el ref y hacer que devuelva los niños con un estilo actualizado y un forwardedRef:

|_+_|

Tenemos el accesorio de los niños, por lo que usaremos la API incorporada de React para manipularlos: React.Children.map y React.cloneElement . Cada niño que pasamos tendrá el GridItem pasado como export const GridItem = ({ forwardedRef, ...props }) => ( ); y un estilo de opacidad personalizado. Como se mencionó anteriormente, el GridItemWrapped se adjunta manualmente al elemento DOM en el componente GridItem.

Nota: esto sucederá automágicamente . Creo que está bien para este ejemplo, pero si encuentra que modificar el estilo de los niños de esta manera es demasiado implícito, podría, por ejemplo, pasar styled.div como accesorio aquí y luego decidir sobre el estilo en el propio componente.

Conectando todo

Bien, tenemos todos los componentes básicos, conectemos todo ahora. ref requiere las interacciones de arrastre y el contexto a configurar y el DragItem necesita un proveedor para funcionar correctamente. forwardedRef es un lugar perfecto para hacerlo:

|_+_|

src / index.js

Nota: Esto está fuera del alcance del tutorial, pero es posible que desee explorar otros extremos posteriores de arrastrar y soltar, como toque backend , en el futuro.

Ahora, vayamos a return React.Children.map(children, child => React.cloneElement(child, { forwardedRef: ref, style: containerStyle }) ); , conecte el ref, forwardedRef y forwardedRef:

|_+_|

Todo debería estar funcionando bien a estas alturas, aunque la cuadrícula está vacía. Preparé un pocos elementos de muestra para usar . Siéntase libre de copiarlos y usarlos en el isDragging constructor para inicializar la lista de elementos. Veremos entonces el efecto deseado:

Este es el título de la imagen

Notas al margen

Este es un ejemplo simple sin cosas complejas ni integraciones de API. Hay varias oportunidades para desarrollarlo más.

¿Qué es la moneda de aumento?

Sería posible ampliar react-dnd componente para aceptar un prop como GridContext (que se llamaría en soltar en useDrop ) e indicaría que el arrastre había terminado. Puede usarse para actualizar el back-end o sincronizar otras cosas en toda la aplicación.

Puede extender el src/index.js para albergar dos listas, la cuadrícula principal de trabajo y una de repuesto con las imágenes esperando ser agregadas a la primera.

Me salté esta parte del tutorial, pero se agregaron algunas pruebas simples al GridContext también.

Resumen

Aprendimos a crear una cuadrícula de imágenes con reordenamiento sobre la marcha. Puede construir sobre eso o simplemente tener una idea de cómo abordar escenarios más complejos de arrastrar y soltar.

Todo el proyecto está en el repositorio de GitHub: https://github.com/tfiechowski/react-dnd-grid-tutorial

¡Gracias! No dudes en expresar tu opinión en los comentarios. Soy muy abierto y estoy ansioso por escuchar sus comentarios, ya sean positivos o negativos.

#reactjs #react #javascript # programación

medium.com

Cómo construir una cuadrícula de arrastrar y soltar con React

Cómo construir una cuadrícula de arrastrar y soltar con React En este tutorial, crearemos una cuadrícula de imágenes de arrastrar y soltar en React. El siguiente gif muestra el efecto deseado