Comment utiliser l'API HTML glisserdéposer dans 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
.
- L'événement
dragenter
se déclenche lorsqu'un élément déplacé entre dans une cible de dépôt valide. - L'événement
dragleave
se déclenche lorsqu'un élément déplacé laisse une goutte valide - 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.) - 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.

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:
-
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! ) -
inDropZone
Ce sera un booléen. Nous l'utiliserons pour savoir si nous nous trouvons dans la zone de dépôt ou non. -
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.

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 (
- {f.name}
)
})}
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:


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

Source link