Comment détecter un clic extérieur avec React et les crochets

Photo par Alex Block sur Unsplash

Que signifie "Clic extérieur"?

Vous pouvez penser à cela comme à «l'anti-bouton». Un clic externe est un moyen de savoir si l'utilisateur clique sur tout mais sur un composant spécifique. Vous avez peut-être constaté ce comportement lors de l'ouverture d'un menu déroulant ou d'une liste déroulante et d'un clic en dehors de celui-ci pour le fermer.

Il existe toutes sortes d’autres cas d’utilisation pour une telle fonctionnalité:

  • lors de la fermeture des listes déroulantes
  • lors de la fermeture des fenêtres modales
  • lors de la transition en mode édition pour les éléments modifiables
  • fermeture
  • et beaucoup plus…

Voyons maintenant comment écrire un composant React générique et réutilisable qui incorporera ce comportement.

À quoi ça va ressembler

Un bon flux devrait ressembler à ceci:

Structure de composant

Pour que ce composant fonctionne, nous devons associer un gestionnaire d’événements click au document lui-même. Cela nous aidera à détecter quand nous cliquons n'importe où sur la page. Ensuite, nous devrons vérifier si notre cible cliquée diffère de notre élément enveloppé. Donc, une structure de base ressemblera à ceci:

Pour le premier exemple, nous commencerons à coder en utilisant le style de la classe React, puis nous le restructurerons avec la nouvelle API Hooks.

Nous avons mis en œuvre deux fonctions de cycle de vie:

  • composantDidMount (): attachera l'écouteur d'événement
  • composantWillUnmount (): nettoie le gestionnaire de clics avant que le composant ne soit détruit

et ensuite nous rendons tout ce que les composants bouclent. Pour notre premier exemple ci-dessus, il rendra le .

La condition «ClickOutside»

Nous devons maintenant vérifier si l'utilisateur clique en dehors de l'enfant enveloppé. Une solution naïve consiste à comparer l’élément cible (l’élément sur lequel nous cliquons) avec le nœud de notre enfant. Mais cela ne fonctionnera que si nous avons un nœud simple (niveau unique) en tant qu'enfant. Si notre enfant enveloppé a plus de sous-nœuds, cette solution échouera.

Heureusement, il existe une méthode appelée .contains () qui nous indique si un nœud est un enfant d'un nœud donné. La prochaine étape consistera à accéder au nœud de notre enfant. Pour ce faire, nous utiliserons les références React.

Les références sont le moyen utilisé par React pour nous donner accès à l’objet noeud brut. Nous allons également utiliser l’API de Reacts pour gérer les composants this.props.children. Nous avons besoin de cette API car nous allons injecter notre référence créée à notre enfant emballé. Gardant cela à l'esprit, notre composant ressemblera à ceci:

Parfait, cela devrait fonctionner comme prévu. Au moins pour notre joyeux flux (un enfant emballé). Si nous avons l'intention d'envelopper plusieurs nœuds, nous devons procéder à quelques ajustements:

  • nous avons besoin d'un tableau de références (autant que nos enfants emballés)
  • nous devons utiliser React.Children.map pour cloner chaque enfant et injecter les références associées à partir de notre tableau privé de références

Cela devrait faire l'affaire. Maintenant, refactorisons cela à l’aide de Hooks!

Crochets

React 16.8 a introduit une nouvelle API appelée Hooks. Avec Hooks, nous pouvons écrire moins de code et obtenir une empreinte plus petite sur notre base de code. De plus, les crochets tirent parti de fonctions qui sont des citoyens de première classe en JavaScript. Si vous connaissez les composants fonctionnels sans état dans React, vous êtes à mi-chemin. Notre refactor initial ressemblera à ceci:

Jusqu'à présent, nous utilisions encore «l'ancienne» API React pour déclarer un composant fonctionnel simple sans état. Cependant, nous avons toujours besoin de ces fonctions de cycle de vie pour attacher notre gestionnaire au nœud du document.

Voici où le crochet d’effet entre en jeu. Le crochet d’effet remplacera nos méthodes «composantDidMount» et «composantWillUnmount». Le crochet d'effet sera appelé juste après le rendu des composants, ce qui nous aidera à attacher le gestionnaire souhaité à temps. Également pour la partie nettoyage, si le raccord Effet renvoie une fonction, cette fonction sera appelée juste avant que le composant ne soit démonté. C'est donc le bon moment pour faire un peu de ménage. Dans le prochain refactor, les choses deviendront un peu plus claires.

C'est la forme finale de notre composant fonctionnel utilisant le crochet à effets. Si vous voulez voir les deux exemples en action, vous pouvez les exécuter ci-dessous. (Vous pouvez exporter par défaut le composant Classe ou le composant fonctionnel et l'application se comportera de la même manière.)

Conclusion

Même si le comportement de clic extérieur est une fonctionnalité largement utilisée, il peut ne pas être aussi simple à implémenter dans React. Avec cet exemple, j'ai pris la liberté d'expérimenter un peu avec React Hooks et de construire la solution de deux manières pour comparer les deux approches. Je suis un grand fan de composants fonctionnels, et maintenant, avec l'aide de Hooks, nous pouvons les amener au niveau supérieur.