web-dev-qa-db-fra.com

Réagissez pour empêcher la propagation des événements dans les composants imbriqués au clic

Voici un composant de base. <ul> et <li> ont tous deux des fonctions onClick. Je veux seulement que l'onClick sur le <li> se déclenche, pas le <ul>. Comment puis-je atteindre cet objectif?

J'ai joué avec e.preventDefault (), e.stopPropagation (), en vain. 

class List extends React.Component {
  constructor(props) {
    super(props);
  }

  handleClick() {
    // do something
  }

  render() {

    return (
      <ul 
        onClick={(e) => {
          console.log('parent');
          this.handleClick();
        }}
      >
        <li 
          onClick={(e) => {
            console.log('child');
            // prevent default? prevent propagation?
            this.handleClick();
          }}
        >
        </li>       
      </ul>
    )
  }
}

// => parent
// => child
50
dmwong2268

J'ai eu le même problème. J'ai trouvé stopPropagation did work. Je scinderais l'élément de la liste en un composant séparé, comme suit:

class List extends React.Component {
  handleClick = e => {
    // do something
  }

  render() {
    return (
      <ul onClick={this.handleClick}>
        <ListItem onClick={this.handleClick}>Item</ListItem> 
      </ul>
    )
  }
}

class ListItem extends React.Component {
  handleClick = e => {
    e.stopPropagation();
    this.props.onClick();
  }

  render() {
    return (
      <li onClick={this.handleClick}>
        {this.props.children}
      </li>       
    )
  }
}
74
Will Stone

React utilise la délégation d’événements avec un seul écouteur d’événements sur le document pour les événements masqués, comme «clic» dans cet exemple, ce qui signifie qu’arrêter la propagation n’est pas possible; l'événement réel s'est déjà propagé au moment où vous interagissez avec lui dans React. stopPropagation sur l'événement synthétique de React est possible car React gère la propagation d'événements synthétiques en interne.

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
}
35
Priyanshu Chauhan

Ce n’est pas idéal à 100%, mais s’il est trop pénible de transmettre props chez les enfants -> mode pour enfants ou créer un Context.Provider/Context.Consumer juste à cet effet), et vous avez affaire à une autre bibliothèque qui a son propre gestionnaire, elle tourne avant la vôtre, vous pouvez aussi essayer:

   function myHandler(e) { 
        e.persist(); 
        e.nativeEvent.stopImmediatePropagation();
        e.stopPropagation(); 
   }

D'après ce que j'ai compris, la méthode event.persist empêche un objet d'être immédiatement renvoyé dans le pool SyntheticEvent de React. Donc, à cause de cela, la event passée dans React n’existe plus au moment où vous l’atteignez! Cela se produit chez les petits-enfants à cause de la manière dont React gère les choses en interne en vérifiant d'abord que le parent est en déshérence pour les gestionnaires SyntheticEvent (surtout si le parent avait un rappel).

Tant que vous n'appelez pas persist sur quelque chose qui créerait une mémoire importante pour continuer à créer des événements tels que onMouseMove (et que vous ne créez pas une sorte de jeu Cookie Clicker comme celui de Grandma's Cookies), tout devrait bien se passer!

Remarquez également: en lisant de temps en temps autour de leur GitHub, nous devrions surveiller de près les versions futures de React car ils peuvent résoudre éventuellement une partie de la douleur liée à cela, car ils semblent vouloir créer du code React de pliage. un compilateur/transpiler.

1
rob2d

La nouvelle façon de procéder est beaucoup plus simple et vous fera gagner du temps! Passez simplement l'événement dans le gestionnaire de clics d'origine et appelez preventDefault();.

clickHandler(e){
    e.preventDefault();
    //Your functionality here
}
0
Austin Rowe

J'ai eu des problèmes à faire fonctionner event.stopPropagation(). Si vous aussi, essayez de le placer en haut de votre fonction de gestionnaire de clics, c’est ce que je devais faire pour empêcher l’événement de se propager. Exemple de fonction: 

  toggleFilter(e) {
    e.stopPropagation(); // If moved to the end of the function, will not work
    let target = e.target;
    let i = 10; // Sanity breaker

    while(true) {
      if (--i === 0) { return; }
      if (target.classList.contains("filter")) {
        target.classList.toggle("active");
        break;
      }
      target = target.parentNode;
    }
  }
0
Nenotlep

Vous pouvez éviter la propagation d'événements en vérifiant la cible de l'événement.
Par exemple, si une entrée est imbriquée dans l'élément div où vous avez le gestionnaire pour l'événement click, et que vous ne voulez pas la gérer, lorsque vous cliquez sur l'entrée, vous pouvez simplement passer event.target dans votre handler et check is handler doivent être exécutés en fonction des propriétés de la cible.
Par exemple, vous pouvez vérifier if (target.localName === "input") { return}.
C'est donc un moyen "d'éviter" l'exécution du gestionnaire