Tıklandığında yuvalanmış bileşenlerde olay köpürmesini önlemeye tepki ver


116

İşte temel bir bileşen. Hem ve <ul>hem <li>de onClick işlevlerine sahiptir. Sadece onClick on the fire'ın <li>ateşlenmesini istiyorum <ul>,. Bunu nasıl başarabilirim?

E.preventDefault (), e.stopPropagation () ile boşuna oynadım.

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

Yanıtlar:


163

Ben de aynı sorunu yaşadım. Ben stopPropagation bulundu yaptım çalışmalarını. Liste öğesini ayrı bir bileşene bölerdim, şöyle ki:

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();  //  <------ Here is the magic
    this.props.onClick();
  }

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

Olmamalı this.props.handleClick()içinde ListItembileşeni this.props.click?
blankface

3
StopPropogation dışında başka bir yol var mı?
Ali Sajid

Peki ya yerel bileşen gibi<Link>
samayo

ya handleClick'e parametreler aktarmanız gerekirse?
Manticore

Bu yanlış soruyu yanıtlamıyor mu? OP, ListItem'in olayı işlemesini istedi. Çözüm, onu ele alan Listeye sahiptir. (Bir şeyi yanlış anlamıyorsam.)
Thomas Jay Rush

57

React, bu örnekteki 'tıklama' gibi kabarcık oluşturan olaylar için belgede tek bir olay dinleyicisiyle olay yetkilendirmesini kullanır; bu, yayılmayı durdurmanın mümkün olmadığı anlamına gelir; gerçek olay, React'te onunla etkileşim kurduğunuzda zaten yayılmıştır. React'in sentetik olayında stopPropagation mümkündür çünkü React, sentetik olayların dahili olarak yayılmasını yönetir.

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

süper kullanışlı .. stopPropagation () kendi başına düzgün çalışmıyordu
pravin

1
Benim için işe document.addEventListener('click')onClick
yarayan

2
Bazen bu işe yaramayabilir - örneğin Material-UI (www.material-ui.com) gibi bir kitaplık kullanıyorsanız veya işleyicilerinizi başka bir bileşenin geri aramasına sarıyorsanız. Ama doğrudan kendi kodunuz varsa, sorun yok!
rob2d

1
@ rob2d, peki Material-UI kullanırken bununla nasıl başa çıkılır?
Italik

@İtalik yukarıda örnek bir fonksiyon var; ancak geri aramada ilk şey olarak hemen aramanız gerekir, böylece sanallaştırılmaz / yutulmaz. En azından AFAIK. Neyse ki son zamanlarda bununla savaşmadım.
rob2d

9

DOM olaylarının sırasına göre: YAKALAMA - BUBBLING

Olayların nasıl yayılacağına dair iki aşama vardır. Bunlara "yakalama" ve "köpürme" denir .

               | |                                   / \
---------------| |-----------------   ---------------| |-----------------
| element1     | |                |   | element1     | |                |
|   -----------| |-----------     |   |   -----------| |-----------     |
|   |element2  \ /          |     |   |   |element2  | |          |     |
|   -------------------------     |   |   -------------------------     |
|        Event CAPTURING          |   |        Event BUBBLING           |
-----------------------------------   -----------------------------------

Önce yakalama aşaması gerçekleşir ve ardından köpürme aşaması gelir. Normal DOM api kullanarak bir olay kaydettiğinizde, olaylar varsayılan olarak köpürme aşamasının bir parçası olacaktır, ancak bu olay oluşturulduktan sonra belirtilebilir.

// CAPTURING event
button.addEventListener('click', handleClick, true)

// BUBBLING events
button.addEventListener('click', handleClick, false)
button.addEventListener('click', handleClick)

React'te, köpürme olayları da varsayılan olarak kullandığınız şeydir.

// handleClick is a BUBBLING (synthetic) event
<button onClick={handleClick}></button>

// handleClick is a CAPTURING (synthetic) event
<button onClickCapture={handleClick}></button>

HandleClick geri aramamıza (React) bir göz atalım:

function handleClick(e) {
  // This will prevent any synthetic events from firing after this one
  e.stopPropagation()
}
function handleClick(e) {
  // This will set e.defaultPrevented to true
  // (for all synthetic events firing after this one)
  e.preventDefault()  
}

Burada bahsetmediğim bir alternatif

Tüm etkinliklerinizde e.preventDefault () 'u çağırırsanız, bir olayın önceden işlenip işlenmediğini kontrol edebilir ve tekrar işlenmesini önleyebilirsiniz:

handleEvent(e) {
  if (e.defaultPrevented) return  // Exits here if event has been handled
  e.preventDefault()

  // Perform whatever you need to here.
}

Yapay olaylar ve yerel olaylar arasındaki fark için, React belgelerine bakın: https://reactjs.org/docs/events.html


5

Bu% 100 ideal değildir, ancak propsçocuklarda geçmek için çok fazla acı varsa -> çocuk modası veya sadece bu amaç için bir Context.Provider/ yaratın ) ve kendi işleyicisi olan başka bir kitaplıkla uğraşıyorsanız çalıştırır sizinkinden önce şunları da deneyebilirsiniz:Context.Consumer

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

Anladığım kadarıyla event.persistyöntem , bir nesnenin hemen React'in SyntheticEventhavuzuna geri atılmasını engelliyor . Bu nedenle, eventReact'te geçirilen aslında siz ona ulaştığınız zaman varolmaz! Bu, torunlarda React'in olayları dahili olarak ele alma biçimi nedeniyle, önce ebeveyni SyntheticEventişleyiciler için aşağı kontrol ederek olur (özellikle ebeveynin bir geri araması varsa).

(Ve Büyükannemin Kurabiyeleri gibi bir tür Cookie Clicker oyunu yaratmıyorsanız) gibi persistetkinlikler oluşturmaya devam etmek için önemli bir hafıza oluşturacak bir şeyi çağırmadığınız sürece onMouseMove, mükemmel bir şekilde iyi olmalı!

Ayrıca not: Ara sıra GitHub'larını okurken, bir derleyicide / aktarıcıda katlanan React kodu oluşturmaya doğru gidiyor gibi göründükleri için , sonunda bu ağrının bir kısmını çözebileceklerinden , gelecekteki React sürümleri için gözlerimizi açık tutmalıyız.


1

Çalışırken sorun yaşadım event.stopPropagation(). Siz de yaparsanız, tıklama işleyici işlevinizin en üstüne taşımayı deneyin, olayın köpürmesini durdurmak için yapmam gereken şey buydu. Örnek işlev:

  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

Olay hedefini kontrol ederek olay köpürmesini önleyebilirsiniz.
Örneğin, tıklama olayı için işleyicinizin olduğu div öğesine iç içe girişiniz varsa ve onu işlemek istemiyorsanız, giriş tıklandığında, yalnızca event.targetişleyicinize geçebilirsiniz ve kontrol işleyicisine göre yürütülmelidir. hedefin özellikleri.
Örneğin kontrol edebilirsiniz if (target.localName === "input") { return}.
Bu, işleyicinin yürütülmesini "önlemenin" bir yolu


-4

Bunu yapmanın yeni yolu çok daha basit ve size biraz zaman kazandıracak! Etkinliği orijinal tıklama işleyicisine aktarın ve arayın preventDefault();.

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

3
-1; Bunu test ettim ve tıklama yayılımı için çalışmıyor. AFAIK bu, temel bağlantı işlevini durduran, ancak olay köpürmesi için olmayan bağlantılar için bir onClick işleyicisi istiyorsanız yararlı olacaktır.
Joel Peltonen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.