Drag and Drop este o tehnică comună de interacțiune adăugată pentru a permite oamenilor să mute intuitiv lucrurile pe o pagină. Acest lucru ar putea fi reordonarea unei liste sau chiar realizarea unui puzzle.

Cum putem adăuga acea interacțiune atunci când construim o aplicație React cu React Beautiful DnD?

  • Ce este Drag and Drop?
  • Ce este React Beautiful DnD?
  • Ce vom construi?
  • Pasul 0: crearea unei noi aplicații React.js
  • Pasul 1: Instalarea React Beautiful DnD
  • Pasul 2: Crearea unei liste glisabile și dropabile cu React Beautiful DnD
  • Pasul 3: Salvarea comenzii listei după reordonarea articolelor cu React Beautiful DnD

Ce este Drag and Drop?

Trageți și fixați este cam ceea ce sună – este o interacțiune care permite unei persoane să facă clic și să trageți un element, apoi să-l plasați în altă parte, având adesea un efect secundar în cadrul aplicației.

Cum se adauga Drag and Drop in React cu React
Mutarea obiectelor pe o tablă

Acest efect este destul de frecvent în aplicații precum listele de sarcini sau tabloul de bord de gestionare a proiectelor, unde trebuie să acordați prioritate și să creați o comandă pentru modul în care ar trebui să se facă lucrurile.

În timp ce glisați și fixați poate avea unele cazuri de utilizare avansate, vom rămâne la funcționalitatea listei de bază pentru pasul nostru.

Ce este React Beautiful DnD?

React Beautiful DnD este o bibliotecă accesibilă cu drag and drop de la Atlassian. Dacă nu știi de Atlassian, ei sunt echipa din spatele lui Jira. Dacă nu sunteți familiarizați cu Jira, este probabil cel mai mare instrument Agile de pe internet chiar acum.

Obiectivele echipei au fost să ofere capabilități de drag and drop cu accesibilitatea în minte, pe lângă menținerea noaptii și performanța cu un API puternic.

Ce vom construi?

Vom începe cu o listă simplă și vom adăuga posibilitatea de a trage și plasa.

În această prezentare generală, nu vom petrece timp construind lista în sine. Lista pe care o vom folosi folosește o listă standard neordonată (<ul>) și elemente de listă (<li>) pentru a crea o listă cu un pic de CSS pentru a face să arate ca niște cărți.

Ne vom concentra pe adăugarea capacității de glisare și plasare pentru a rearanja lista folosind React Beautiful DnD.

Pasul 0: crearea unei noi aplicații React.js

Pentru a începe, dorim o aplicație simplă care să conțină o listă de articole. Acesta poate fi un proiect existent sau un proiect nou, folosind cadrul preferat, cum ar fi Creați aplicația React.

Am început cu o aplicație nouă folosind aplicația Create React și am adăugat o listă simplă de Spațiul final personaje.

Cum se adauga Drag and Drop in React cu React
Lista de caractere Final Space

Dacă doriți să începeți din același loc, puteți clona depozitul meu demo la acea sucursală și puteți începe chiar împreună cu mine.

Această comandă se va clona ramura specifică pentru a incepe:

git clone --single-branch --branch part-0-starting-point git@github.com:colbyfayock/my-final-space-characters.git

În caz contrar, puteți clona depozitul ca de obicei și verificați filiala part-0-starting-point.

Dacă doriți să urmați doar codul, am creat mai întâi o serie de obiecte:

const finalSpaceCharacters = [
  {
    id: 'gary',
    name: 'Gary Goodspeed',
    thumb: '/images/gary.png'
  },
  ...

And then I loop through them to create my list:

<ul className="characters">
  {finalSpaceCharacters.map(({id, name, thumb}) => {
    return (
      <li key={id}>
        <div className="characters-thumb">
          <img src={thumb} alt={`${name} Thumb`} />
        </div>
        <p>
          { name }
        </p>
      </li>
    );
  })}
</ul>

Follow along with the commit!

Step 1: Installing React Beautiful DnD

First step is to install the library via npm.

Inside of your project, run the following:

yarn add react-beautiful-dnd
# or
npm install react-beautiful-dnd --save

This will add the library to our project and we’ll be ready to use it in our app.

Step 2: Making a list draggable and droppable with React Beautiful DnD

With our library installed, we can give our list the ability to drag and drop.

Adding Drag and Drop context to our app

At the top of the file, import DragDropContext from the library with:

import { DragDropContext } from 'react-beautiful-dnd';

DragDropContext is going to give our app the ability to use the library. It works similarly to React’s Context API, where the library can now have access to the component tree.

Note: If you plan on adding drag and drop to more than one list, you need to make sure that your DragDropContext wraps all of those items, like at the root of your application. You can not nest DragDropContext.

We’ll want to wrap our list with DragDropContext:

<DragDropContext>
  <ul className="characters">
  ...
</DragDropContext>

At this point, nothing will have changed with the app and it should still load as it did before.

Making our list a Droppable area

Next, we want to create a Droppable area, meaning, this will allow us to provide a specific area where our items can be moved around inside.

First, add Droppable to our import at the top of the file:

import { DragDropContext, Droppable } from 'react-beautiful-dnd';

For our purpose, we want our entire unordered list (<ul>) to be our drop zone, so we’ll again want to wrap it with this component:

<DragDropContext>
  <Droppable droppableId="characters">
    {(provided) => (
      <ul className="characters">
        ...
      </ul>
    )}
  </Droppable>
</DragDropContext>

You’ll notice we wrapped it a bit differently this time though. First, we set a droppableId on our <Droppable> component. This allows the library to keep track of this specific instance between interactions.

We’re also creating a function immediately inside of that component that passes in the provided argument.

Note: This function can pass in two arguments including a snapshot argument, but we won’t be using it in this example.

The provided argument include information and references to code that the library needs to work properly.

To use it, on our list element, let’s add:

<ul className="characters" {...provided.droppableProps} ref={provided.innerRef}>

This is going to create a reference (provided.innerRef) for the library to access the list element’s HTML element.  It also applies props to the element (provided.droppableProps) that allows the library to keep track of movements and positioning.

Again, at this point, there won’t be any noticeable functionality.

Making our items Draggable

Now for the fun part!

The final piece of making our list elements draggable and droppable is wrapping each list item with a component similar to what we just did with the entire list.

We’ll be using the Draggable component, which again, similar to the Droppable component, will include a function where we’ll pass through props to our list item components.

First, we need to import Draggable along with the rest of the components.

import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

Next, inside of our loop, let’s wrap the returning list item with the <Draggable /> component and it’s top level function.

{finalSpaceCharacters.map(({id, name, thumb}) => {
  return (
    <Draggable>
      {(provided) => (
        <li key={id}>
          ...
        </li>
      )}
    </Draggable>

Because we now have a new top level component in our loop, let’s move the key prop from the list element to Draggable:

{finalSpaceCharacters.map(({id, name, thumb}) => {
  return (
    <Draggable key={id}>
      {(provided) => (
        <li>

We also need to set two addition props on <Draggable>, a draggableId and an index.

We’ll want to add index as an argument into our map function and then include those props on our component:

{finalSpaceCharacters.map(({id, name, thumb}, index) => {
  return (
    <Draggable key={id} draggableId={id} index={index}>

Finally, we need to set some props on the list element itself.

On our list element, add this ref and spread additional props from the provided argument:

<Draggable key={id} draggableId={id} index={index}>
  {(provided) => (
    <li ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>

Now, if we refresh our page, and hover over our list items, we can now drag them around!

1611890109 508 Cum se adauga Drag and Drop in React cu React
Dragging items on a list

However, you’ll notice that when you start moving an item around, the bottom of the page appears to be a little messed up. There’s some overflow issues with our list items and our footer.

You’ll also notice that in the developer console, React Beautiful DnD is giving us a warning message that we’re missing something called a placeholder.

1611890109 151 Cum se adauga Drag and Drop in React cu React
Console warning – placeholder could not be found

Adding a placeholder from React Beautiful DnD

Part of React Beautiful DnD’s requirements is that we additionally include a placeholder item.

This is something that they provide out of the box, but this is used to fill up the space that the item we’re dragging previously took.

To add that, we want to include provided.placeholder at the bottom of our Droppable top level list component, in our case at the bottom of the <ul>:

<Droppable droppableId="characters">
  {(provided) => (
    <ul className="characters" {...provided.droppableProps} ref={provided.innerRef}>
      ...
      {provided.placeholder}
    </ul>
  )}
</Droppable>

And if we start dragging things around in our browser, we can see that our page flow doesn’t have issues and the content stays where it should!

1611890109 407 Cum se adauga Drag and Drop in React cu React
Dragging items with fixed spacing

The last issue though, is when you move something around, it doesn’t stay, so how can we save the order of our items?

Follow along with the commit!

Step 3: Saving list order after reordering items with React Beautiful DnD

When we move our items, they stay where they land for a split second. But after React Beautiful DnD finishes doing its work, our component tree will rerender.

When the components rerender, our items go back to the same place that they were before, because we never saved that outside of DnD’s memory.

To resolve this, DragDropContext takes in an onDragEnd prop that will allow us to fire a function after dragging has complete. That function passes in arguments that includes the new order of our items so that we can update our state for the next render cycle.

Saving our list items in state

First, let’s store our items in state so that we’ll have something to update between cycles.

At the top of the file, add useState to the React import:

import React, { useState } from 'react';

Then, we’re going to create our state using our default list of items.

Add the following to the top of our App component:

const [characters, updateCharacters] = useState (finalSpaceCharacters);

Pentru că vom actualiza noul nostru characters pentru a furniza elementele listei noastre și comanda lor, acum vom dori să înlocuim matricea pe care o mapăm în noua noastră stare:

<ul className="characters" {...provided.droppableProps} ref={provided.innerRef}>
  {characters(({id, name, thumb}, index) => {

Și dacă salvăm și actualizăm pagina noastră, nimic nu ar trebui să se schimbe!

Actualizarea stării la tragerea articolelor

Acum, că avem starea noastră, putem actualiza starea respectivă de fiecare dată când elementele listei noastre sunt trase.

DragDropContext componentă pe care am adăugat-o pe pagina noastră este inclusă într-o prop onDragEnd. După cum sună, aceasta va declanșa o funcție ori de câte ori cineva nu mai trage un element din listă.

Să adăugăm o funcție handleOnDragEnd drept prop:

<DragDropContext onDragEnd={handleOnDragEnd}>

Apoi, avem nevoie ca acea funcție să existe de fapt.

Putem defini o funcție în starea noastră:

function handleOnDragEnd(result) {
}

Funcția noastră acceptă un argument numit result.

Dacă adăugăm console.log(result) la funcția și mutarea unui element din lista noastră, putem vedea că include detalii despre care ar trebui să fie starea actualizată după acțiunea noastră de mutare.

1611890109 767 Cum se adauga Drag and Drop in React cu React
Rezultatul elementului glisat

În special, vrem să folosim index valoare atât în destination și source proprietăți, care ne indică indexul articolului care este mutat și care ar trebui să fie noul index al acelui element în matricea de articole.

Deci, folosind asta, să adăugăm următoarele la funcția noastră:

const items = Array.from(characters);
const [reorderedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, reorderedItem);

updateCharacters(items);

Iată ce facem:

  • Creăm o nouă copie a noastră characters matrice
  • Noi folosim source.index valoare pentru a găsi articolul nostru din noua noastră matrice și a-l elimina folosind splice metodă
  • Acest rezultat este destructurat, așa că ajungem cu un nou obiect al reorderedItem acesta este elementul nostru tras
  • Ne folosim apoi de destination.inddex pentru a adăuga acel element înapoi în matrice, dar la locația nouă, folosind din nou splice
  • În cele din urmă, le actualizăm characters starea folosind updateCharacters funcţie

Și acum, după ce ne-am salvat funcția, ne putem mișca personajele și își salvează locația!

1611890109 198 Cum se adauga Drag and Drop in React cu React
Trageți elementul cu starea salvată

Prevenirea tragerii erorilor în afara limitelor

O problemă cu implementarea noastră este că, dacă cineva nu trage articolul exact în containerele definite, vom primi o eroare.

1611890109 30 Cum se adauga Drag and Drop in React cu React
Eroare la tragerea din container

Problema este că, atunci când îl tragem în afara containerului definit, nu avem o destinație.

Pentru a evita acest lucru, putem adăuga pur și simplu o declarație deasupra codului care mută elementul în jurul nostru, care verifică dacă destinația există și, dacă nu, iese din funcție:

function handleOnDragEnd(result) {
  if (!result.destination) return;

Și dacă reîncarcăm pagina și încercăm să scoatem din nou articolul, articolul nostru se întoarce înapoi la locația inițială fără o eroare!

1611890110 565 Cum se adauga Drag and Drop in React cu React
Faceți clic înapoi atunci când este scos din container

Urmați împreună cu comiterea!

Ce mai putem face cu React Beautiful DnD?

Stiluri personalizate la tragere și plasare

Când mutați articole, DnD va oferi un instantaneu al stării date. Cu aceste informații, putem aplica stiluri personalizate astfel încât, atunci când ne mutăm articolele, să putem afișa o stare activă pentru listă, elementul pe care îl mutăm sau ambele!

https://react-beautiful-dnd.netlify.app/?path=/story/single-vertical-list–basic

Tragerea între diferite liste

Dacă ați mai folosit Trello sau un instrument de genul acesta, ar trebui să vă familiarizați cu conceptul diferitelor coloane între care puteți trage cărți, astfel încât să puteți prioritiza și să vă organizați sarcinile și ideile.

Această bibliotecă vă permite să faceți același lucru, oferind posibilitatea de a trage și plasa articole dintr-o zonă glisabilă în alta.

https://react-beautiful-dnd.netlify.app/?path=/story/multiple-vertical-lists–stress-test