Fermer

février 19, 2020

Comment utiliser l'API HTML glisserdéposer dans React


À propos de l'auteur

Génial développeur frontend qui adore tout le codage. Je suis un amoureux de la musique chorale et je travaille pour la rendre plus accessible au monde, un téléchargement à la…
En savoir plus sur
Chidi

Dans ce didacticiel, nous allons créer un composant glisser-déposer React pour les téléchargements de fichiers et d'images. Au cours de ce processus, nous découvrirons l'API de glisser-déposer HTML. Nous apprendrons également à utiliser le crochet useReducer pour gérer l'état dans un composant fonctionnel React.

L'API glisser-déposer est l'une des fonctionnalités les plus intéressantes de HTML. Il nous aide à implémenter des fonctionnalités de glisser-déposer dans les navigateurs Web.

Dans le contexte actuel, nous allons faire glisser des fichiers depuis l'extérieur du navigateur. Lors de la suppression du ou des fichiers, nous les mettons sur une liste et affichons leurs noms. Avec les fichiers en main, nous pourrions alors effectuer une autre opération sur le (s) fichier (s), par ex. téléchargez-les sur un serveur cloud.

Dans ce didacticiel, nous allons nous concentrer sur la façon d'implémenter l'action de glisser-déposer dans une application React. Si vous avez besoin d'une implémentation JavaScript simple vous voudrez peut-être d'abord lire « Comment créer un téléchargeur de fichiers par glisser-déposer avec JavaScript Vanilla », un excellent didacticiel écrit par Joseph Zimmerman il n'y a pas si longtemps.

Le dragenter dragleave dragover Et drop Événements

Là sont huit événements de glisser-déposer différents. Chacun se déclenche à un stade différent de l'opération de glisser-déposer. Dans ce didacticiel, nous nous concentrerons sur les quatre éléments déclenchés lorsqu'un élément est déposé dans une zone de dépôt: dragenter dragleave dragover et drop .

  1. L'événement dragenter se déclenche lorsqu'un élément déplacé entre dans une cible de dépôt valide.
  2. L'événement dragleave se déclenche lorsqu'un élément déplacé laisse une goutte valide
  3. L'événement de survol se déclenche lorsqu'un élément déplacé est glissé sur une cible de dépôt valide. (Il se déclenche toutes les quelques centaines de millisecondes.)
  4. L'événement drop se déclenche lorsqu'un élément tombe sur une cible de dépôt valide, c'est-à-dire qu'il est glissé et relâché.

Nous pouvons transformer n'importe quel élément HTML en un élément valide supprimer la cible en définissant les attributs de gestionnaire d'événements ondragover et ondrop .

Vous pouvez tout savoir sur les huit événements des documents Web MDN .

Événements glisser-déplacer dans React

Pour commencer, clonez le référentiel du didacticiel à partir de cette URL:

 https://github.com/chidimo/react-dnd.git

Consultez la branche 01-start . Assurez-vous que le fil est également installé. Vous pouvez l'obtenir sur yarnpkg.com .

Mais si vous préférez, créez un nouveau projet React et remplacez le contenu de App.js par le code ci-dessous:

 importer React à partir de 'react';
import './App.css';

fonction App () {
  revenir (
    

Composant glisser-déposer React

); } exporter l'application par défaut;

Remplacez également le contenu de App.css par le style CSS ci-dessous:

 .App {
  marge: 2rem;
  alignement du texte: centre;
}
h1 {
  couleur: # 07F;
}
.drag-drop-zone {
  rembourrage: 2rem;
  alignement du texte: centre;
  fond: # 07F;
  rayon-frontière: 0,5rem;
  boîte-ombre: 5px 5px 10px # C0C0C0;
}
.drag-drop-zone p {
  couleur: #FFF;
}
.drag-drop-zone.inside-drag-area {
  opacité: 0,7;
}
.dropped-files li {
  couleur: # 07F;
  rembourrage: 3px;
  alignement du texte: gauche;
  poids de police: gras;
}

Si vous avez cloné le dépôt, émettez les commandes suivantes (dans l'ordre) pour démarrer l'application:

 yarn # install dependencies
fil démarrer # démarrer l'application

L'étape suivante consiste à créer un composant glisser-déposer. Créez un fichier DragAndDrop.js dans le dossier src / . Entrez la fonction suivante dans le fichier:

 import React from 'react';

const DragAndDrop = props => {
  const handleDragEnter = e => {
    e.preventDefault ();
    e.stopPropagation ();
  };
  const handleDragLeave = e => {
    e.preventDefault ();
    e.stopPropagation ();
  };
  const handleDragOver = e => {
    e.preventDefault ();
    e.stopPropagation ();
  };
  const handleDrop = e => {
    e.preventDefault ();
    e.stopPropagation ();
  };
  revenir (
    
handleDrop (e)}       onDragOver = {e => handleDragOver (e)}       onDragEnter = {e => handleDragEnter (e)}       onDragLeave = {e => handleDragLeave (e)}     >       

Faites glisser les fichiers ici pour les télécharger

); }; exporter DragAndDrop par défaut;

Dans le retour div nous avons défini nos attributs de gestionnaire d'événements HTML . Vous pouvez voir que la seule différence par rapport au HTML pur est le boîtier en chameau.

Le div est maintenant une cible de dépôt valide puisque nous avons défini le onDragOver ] et onDrop attributs du gestionnaire d'événements.

Nous avons également défini des fonctions pour gérer ces événements.

Pour chacun des gestionnaires d'événements, nous appelons preventDefault () pour empêcher le navigateur d'exécuter son comportement par défaut. Le comportement par défaut du navigateur consiste à ouvrir le fichier déposé. Nous appelons également stopPropagation () pour nous assurer que l'événement n'est pas propagé des éléments enfant aux parents.

Importez le composant DragAndDrop dans le composant App App et le rendre sous l'en-tête.

 
  

Composant React par glisser-déposer

  

Maintenant, visualisez le composant dans le navigateur et vous devriez voir quelque chose comme l'image ci-dessous.

 Zone de dépôt
div à convertir en zone de dépôt ( Grand aperçu ) [19659039] Si vous suivez le repo, la branche correspondante est 02-start-dragndrop

Gestion de l'état avec le useReducer Hook

Notre prochaine étape sera d'écrire la logique pour chacun de nos gestionnaires d'événements. Avant de faire cela, nous devons réfléchir à la façon dont nous avons l'intention de suivre les fichiers perdus. C'est ici que nous commençons à penser à la gestion des états.

Nous allons suivre les états suivants pendant l'opération de glisser-déposer:

  1. dropDepth
    Ce sera un entier. Nous l'utiliserons pour garder une trace du nombre de niveaux de profondeur dans la zone de largage. Plus tard, je vais l'expliquer avec une illustration. ( Crédits à Egor Egorov pour avoir mis en lumière celui-ci pour moi! )
  2. inDropZone
    Ce sera un booléen. Nous l'utiliserons pour savoir si nous nous trouvons dans la zone de dépôt ou non.
  3. FileList
    Ce sera une liste. Nous allons l'utiliser pour garder une trace des fichiers qui ont été déposés dans la zone de dépôt.

Pour gérer les états, React fournit les crochets useState et useReducer . Nous allons opter pour le crochet useReducer étant donné que nous traiterons des situations où un état dépend de l'état précédent.

Le crochet useReducer accepte un réducteur de type (état, action) => newState et renvoie l'état actuel associé à une méthode dispatch .

Vous pouvez en savoir plus sur useReducer dans le React docs .

À l'intérieur du composant App (avant la déclaration de retour ), ajoutez le code suivant:

. ..
const reducer = (état, action) => {
  commutateur (action.type) {
    cas 'SET_DROP_DEPTH':
      return {... state, dropDepth: action.dropDepth}
    cas 'SET_IN_DROP_ZONE':
      return {... state, inDropZone: action.inDropZone};
    cas 'ADD_FILE_TO_LIST':
      return {... state, fileList: state.fileList.concat (action.files)};
    défaut:
      état de retour;
  }
};
const [data, dispatch] = React.useReducer (
  réducteur, {dropDepth: 0, inDropZone: false, fileList: []}
)
...

Le crochet useReducer accepte deux arguments: un réducteur et un état initial. Il renvoie l'état actuel et une fonction de répartition avec laquelle mettre à jour l'état. L'état est mis à jour en envoyant une action qui contient un type et une charge utile facultative. La mise à jour apportée à l'état du composant dépend de ce qui est renvoyé par l'instruction case à la suite du type d'action. (Notez ici que notre état initial est un objet .)

Pour chacune des variables d'état, nous avons défini une déclaration de cas correspondante pour le mettre à jour. La mise à jour est effectuée en invoquant la fonction dispatch renvoyée par useReducer .

Maintenant, passez data et dispatch en tant qu'accessoires au composant DragAndDrop que vous avez dans votre fichier App.js :

 

En haut du composant DragAndDrop nous pouvons accéder aux deux valeurs à partir des accessoires .

 const {data, dispatch} = props;

Si vous suivez le repo, la branche correspondante est 03-define-reducers .

Terminons la logique de nos gestionnaires d'événements. Notez que les points de suspension représentent les deux lignes:

 e.preventDefault ()
e.stopPropagation ()


const handleDragEnter = e => {
  ...
  dispatch ({type: 'SET_DROP_DEPTH', dropDepth: data.dropDepth + 1});
};

const handleDragLeave = e => {
  ...
  dispatch ({type: 'SET_DROP_DEPTH', dropDepth: data.dropDepth - 1});
  si (data.dropDepth> 0) retourne
  dispatch ({type: 'SET_IN_DROP_ZONE', inDropZone: false})
};

Dans l'illustration qui suit, nous avons imbriqué les zones de largage A et B. A est notre zone d'intérêt. C'est ici que nous voulons écouter les événements de glisser-déposer.

 Une illustration des événements ondragenter et ondragleave
Une illustration des événements ondragenter et ondragleave ( Grand aperçu )

Lorsque vous glissez dans une zone de largage, chaque fois que nous atteignons une limite, l'événement ondragenter est déclenché. Cela se produit aux limites A-in et B-in . Puisque nous entrons dans la zone, nous incrémentons dropDepth .

De même, lorsque vous sortez d'une zone de largage, chaque fois que vous atteignez une limite, l'événement ondragleave est déclenché. Cela se produit aux limites A-out et B-out . Puisque nous quittons la zone, nous décrémentons la valeur de dropDepth . Notez que nous ne définissons pas inDropZone sur false à la limite B-out . C'est pourquoi nous avons cette ligne pour vérifier la dropDepth et le retour de la fonction dropDepth supérieur à 0 .

 if (data.dropDepth> 0) return 

Ceci est car même si l'événement ondragleave est déclenché, nous sommes toujours dans la zone A. Ce n'est qu'après avoir frappé A-out et dropDepth est maintenant 0 que nous avons défini inDropZone sur false . À ce stade, nous avons laissé toutes les zones de dépôt.

 const handleDragOver = e => {
  ...
  e.dataTransfer.dropEffect = 'copier';
  dispatch ({type: 'SET_IN_DROP_ZONE', inDropZone: true});
};

Chaque fois que cet événement se déclenche, nous définissons inDropZone sur true . Cela nous indique que nous sommes à l'intérieur de la zone de largage. Nous avons également défini dropEffect sur l'objet dataTransfer sur copie . Sur un Mac, cela a pour effet d'afficher un signe plus vert lorsque vous faites glisser un élément dans la zone de dépôt.

 const handleDrop = e => {
  ...
  laisser les fichiers = [...e.dataTransfer.files];
  
  if (files && files.length> 0) {
    const existingFiles = data.fileList.map (f => f.name)
    files = files.filter (f =>! existingFiles.includes (f.name))
    
    dispatch ({type: 'ADD_FILE_TO_LIST', fichiers});
    e.dataTransfer.clearData ();
    dispatch ({type: 'SET_DROP_DEPTH', dropDepth: 0});
    dispatch ({type: 'SET_IN_DROP_ZONE', inDropZone: false});
  }
};

Nous pouvons accéder aux fichiers déposés avec e.dataTransfer.files . La valeur est un objet de type tableau, nous utilisons donc la syntaxe d'étalement du tableau pour le convertir en un tableau JavaScript .

Nous devons maintenant vérifier s'il y a au moins un fichier avant d'essayer de l'ajouter à notre gamme de fichiers. Nous nous assurons également de ne pas inclure les fichiers qui se trouvent déjà dans notre fileList .
L'objet dataTransfer est effacé en préparation de la prochaine opération de glisser-déposer. Nous avons également réinitialisé les valeurs de dropDepth et inDropZone .

Mettez à jour le className de la div dans le DragAndDrop composant. Cela modifiera conditionnellement le className de la div en fonction de la valeur de data.inDropZone .

 
  

Faites glisser les fichiers ici pour les télécharger

Rendez la liste des fichiers dans App.js en mappant à travers data.fileList .

 
  

Composant React par glisser-déposer

    {data.fileList.map (f => {       revenir (         
  1. {f.name}
  2.       )     })}   

Maintenant, essayez de faire glisser et de déposer certains fichiers dans la zone de dépôt. Vous verrez que lorsque nous entrons dans la zone de dépôt, l'arrière-plan devient moins opaque car la classe inside-drag-area est activée.

Lorsque vous relâchez les fichiers à l'intérieur de la zone de dépôt, vous voir les noms de fichiers répertoriés sous la zone de dépôt:

 Zone de dépôt présentant une faible opacité pendant le survol
Zone de dépôt affichant une faible opacité pendant le survol ( Grand aperçu )
 Une liste de fichiers déposés dans le zone de dépôt
Une liste de fichiers déposés dans la zone de dépôt ( Grand aperçu )

La version complète de ce didacticiel se trouve dans la branche 04-finish-handlers . [19659089] Conclusion

Nous avons vu comment gérer les téléchargements de fichiers dans React à l'aide de l'API HTML glisser-déposer. Nous avons également appris à gérer l'état avec le crochet useReducer . Nous pourrions étendre la fonction du fichier handleDrop . Par exemple, nous pourrions ajouter une autre vérification pour limiter la taille des fichiers si nous le voulions. Cela peut venir avant ou après la vérification des fichiers existants. Nous pourrions également rendre la zone de dépôt cliquable sans affecter la fonctionnalité de glisser-déposer.

Ressources

 Éditorial fracassant (ra, ks, il)




Source link