क्लिक पर नेस्टेड घटकों में रिएक्शन बबलिंग को रोकें


115

यहाँ एक बुनियादी घटक है। दोनों के पास <ul>और <li>ऑनक्लिक कार्य हैं। मैं केवल <li>आग पर क्लिक करना चाहता हूं , नहीं <ul>। इसे कैसे प्राप्त किया जा सकता है?

मैंने कोई फायदा नहीं होने के लिए e.preventDefault (), e.stopPropagation () के साथ खेला है।

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

मेरे पास एक ही सवाल था, stackoverflow.com/questions/44711549/…

जवाबों:


162

मेरी भी यही समस्या थी। मैंने पाया कि स्टॉपप्रोपैजेशन ने काम किया। मैं सूची आइटम को एक अलग घटक में विभाजित करूँगा, जैसा कि:

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>       
    )
  }
}

घटक this.props.handleClick()में नहीं होना चाहिए ? ListItemthis.props.click
ब्लैंकफेस

3
स्टॉपप्रोपोगेशन को छोड़कर कोई अन्य तरीका?
अली साजिद

देशी घटक के बारे में क्या<Link>
samayo

क्या होगा यदि आपको हैंडल करने के लिए मापदंडों को पारित करने की आवश्यकता है?
मतिकोर

क्या यह गलत प्रश्न का उत्तर नहीं देता है? ओपी ने घटना को संभालने के लिए ListItem के लिए कहा। समाधान में सूची को संभालना है। (जब तक मैं कुछ गलत नहीं समझ रहा हूँ।)
थॉमस जे रश

57

प्रतिक्रिया उस घटना के लिए दस्तावेज़ पर एकल ईवेंट श्रोता के साथ ईवेंट प्रतिनिधिमंडल का उपयोग करती है, जैसे कि इस उदाहरण में 'क्लिक', जिसका अर्थ है कि प्रसार को रोकना संभव नहीं है; वास्तविक घटना पहले ही उस समय तक प्रचारित हो जाती है जब आप इसके साथ प्रतिक्रिया करते हैं। प्रतिक्रिया की सिंथेटिक घटना पर रोक संभव है क्योंकि प्रतिक्रिया आंतरिक रूप से सिंथेटिक घटनाओं के प्रसार को संभालती है।

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

सुपर उपयोगी .. stopPropagation () अपने आप ठीक से काम नहीं कर रहा था
प्रवीण

1
यह मेरे लिए काम कर रहा है क्योंकि मैं document.addEventListener('click')प्रतिक्रिया के साथ संयुक्त का उपयोग कर रहा हूंonClick
ओटोथेरा

2
कभी-कभी यह काम नहीं कर सकता है - उदाहरण के लिए यदि आप सामग्री-यूआई (www.material-ui.com) जैसी लाइब्रेरी का उपयोग कर रहे हैं, या किसी अन्य घटक के कॉलबैक में अपने हैंडलर्स को लपेट रहे हैं। लेकिन अगर आपका अपना कोड सीधे, ठीक है!
रॉबड

1
@ rob2d, तो सामग्री-यूआई का उपयोग करते समय इसके साथ कैसे व्यवहार करें?
इटैलिक

@ इटालिक ऊपर एक नमूना समारोह है; लेकिन आपको इसे कॉलबैक में पहली चीज़ के रूप में तुरंत कॉल करने की आवश्यकता है ताकि यह वर्चुअलाइज्ड / निगल न जाए। कम से कम AFAIK। शुक्र है कि हाल ही में यह एक से जूझ नहीं रहा है।
रोब

9

DOM इवेंट्स के आदेश पर: CAPTURING vs BUBBLING

घटनाओं के प्रचार के लिए दो चरण हैं। इन्हें "कैप्चरिंग" और "बबलिंग" कहा जाता है ।

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

कैप्चरिंग स्टेज पहले होता है, और उसके बाद बबलिंग स्टेज होता है। जब आप नियमित DOM एपीआई का उपयोग करके किसी घटना को पंजीकृत करते हैं, तो ईवेंट डिफ़ॉल्ट रूप से बबलिंग चरण का हिस्सा होगा, लेकिन यह ईवेंट निर्माण पर निर्दिष्ट किया जा सकता है

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

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

प्रतिक्रिया में, बुदबुदाती घटनाएँ भी हैं जो आप डिफ़ॉल्ट रूप से उपयोग करते हैं।

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

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

आइए एक नज़र डालते हैं हमारे हैंडल पर क्लिक करें कॉलबैक (प्रतिक्रिया):

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()  
}

एक विकल्प जो मैंने यहाँ नहीं देखा है

यदि आप अपने सभी ईवेंट में e.preventDefault () कहते हैं, तो आप देख सकते हैं कि क्या कोई ईवेंट पहले ही हैंडल किया जा चुका है, और इसे फिर से हैंडल करने से रोकें:

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

  // Perform whatever you need to here.
}

सिंथेटिक घटनाओं और देशी घटनाओं के बीच अंतर के लिए, प्रतिक्रिया दस्तावेज देखें: https://reactjs.org/docs/events.html


5

यह 100% आदर्श नहीं है, लेकिन अगर यह या तो propsबच्चों में पास होने के लिए बहुत अधिक दर्द है -> बच्चे फैशन या इस उद्देश्य के लिए Context.Provider/ a / Context.Consumer बस बनाते हैं ), और आप एक अन्य पुस्तकालय के साथ काम कर रहे हैं जिसके पास खुद का हैंडलर है आपके सामने, आप भी कोशिश कर सकते हैं:

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

मैं जो समझता हूं, वह event.persistविधि किसी वस्तु को तुरंत रिएक्ट के SyntheticEventपूल में वापस फेंकने से रोकती है । तो उस वजह से, eventप्रतिक्रिया में पारित वास्तव में उस समय तक मौजूद नहीं होता है जब आप इसके लिए पहुंचते हैं! पोते के साथ ऐसा होता है क्योंकि जिस तरह से रिएक्टर हैंडल की चीजों को आंतरिक रूप से पहले SyntheticEventहैंडलर्स के लिए डाउन पर माता-पिता की जांच करके (खासकर यदि माता-पिता को कॉलबैक था)।

जब तक आप persistकिसी ऐसी चीज पर कॉल नहीं कर रहे हैं जो महत्वपूर्ण मेमोरी बनाएगी जैसे कि इवेंट्स बनाते रहना है onMouseMove(और आप किसी तरह के कुकी क्लिकर गेम जैसे दादी के कुकीज़ नहीं बना रहे हैं), यह पूरी तरह से ठीक होना चाहिए!

यह भी ध्यान दें: कभी-कभी उनके गीथहब के आसपास पढ़ने से, हमें अपनी आँखों को प्रतिक्रिया के भविष्य के संस्करणों के लिए बाहर रखना चाहिए क्योंकि वे अंततः इस के साथ कुछ दर्द को हल कर सकते हैं क्योंकि वे एक संकलक / ट्रांसपिलर में फोल्ड रिएक्ट कोड बनाने की ओर जा रहे हैं।


1

मेरे पास event.stopPropagation()काम करने के मुद्दे थे । यदि आप भी ऐसा करते हैं, तो इसे अपने क्लिक हैंडलर फ़ंक्शन के शीर्ष पर ले जाने का प्रयास करें, यही मुझे इस घटना को बुदबुदाहट से रोकने के लिए आवश्यक था। उदाहरण समारोह:

  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

आप ईवेंट के लक्ष्य की जांच करके ईवेंट बबलिंग से बच सकते हैं।
उदाहरण के लिए यदि आपके पास इनपुट तत्व के लिए नेस्टेड है जहां आपके पास क्लिक इवेंट के लिए हैंडलर है, और आप इसे हैंडल नहीं करना चाहते हैं, जब इनपुट क्लिक किया जाता है, तो आप बस event.targetअपने हैंडलर में पास कर सकते हैं और चेक हैंडलर के आधार पर निष्पादित किया जाना चाहिए। लक्ष्य के गुण।
उदाहरण के लिए आप जाँच कर सकते हैं if (target.localName === "input") { return}
तो, यह हैंडलर निष्पादन को "टालने" का एक तरीका है


-4

ऐसा करने का नया तरीका बहुत अधिक सरल है और आपको कुछ समय बचाएगा! बस मूल क्लिक हैंडलर में घटना को पास करें और कॉल करें preventDefault();

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

3
-1; मैंने इसका परीक्षण किया और यह क्लिक प्रचार के लिए काम नहीं करता है। AFAIK यह उपयोगी होगा यदि आप लिंक के लिए एक ऑनक्लियर हैंडलर चाहते हैं जो मूल लिंक कार्यक्षमता को रोकते हैं, लेकिन घटना बुदबुदाती के लिए नहीं।
जोएल पेल्टनन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.