Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React click event bubbling "sideways", not just "up"

I have nested click event handlers within a component:

class ListItem extends React.Component {
    ...
    render() {
        return (
            <div onClick={this.save}>
              ...Content...
              <span onClick={this.onDeleteClick}> (Delete)</span>
            </div>
        );
    }
    ...
}

(Complete, minimal example at the bottom of this post.)

This component is used as a "list item" within a containing component. When I click on the (Delete) it fires the onDeleteClick as expected, which makes a callback to the parent which results in the component being removed from the parent component. The click event then starts bubbling up, as expected. However, it bubbles "up" to the next component in the parent list. After all, the original target was already removed by the delete handler.

If I add an e.stopPropagation() to the top of the onDeleteClick handler it all works fine, but I'm just trying to understand why the click event is being delivered to a completely different component, just to make sure there aren't any other smoking guns in there.

My current theory is that the pending event queue is somehow indexed into the virtual DOM in such a way that if you mutate the virtual DOM during an event handler, bubbling events could get delivered to the incorrect component in the virtual DOM. I would have expected the bubbling event to simply not fire, rather than firing on a completely different component.

Is this what's going on? Any other insight? Is this a flawed design, and if so, any recommendations on alternatives?


Here's a minimal example showing the problem: https://codepen.io/mgalgs/pen/dRJJyB

And here's the fixed version: https://codepen.io/mgalgs/pen/KqZBKp

The full diff for the "fix" is:

--- orig.jsx
+++ new.jsx
@@ -32,6 +32,7 @@
     }

     onDeleteClick(e) {
+        e.stopPropagation();
         this.props.onDeleteClick(e);
     }
 }
like image 381
mgalgs Avatar asked Jun 29 '17 00:06

mgalgs


1 Answers

+1 Thanks for posting an interesting question.

The behaviour seems inline with W3C's recommendations that:

The chain of EventTargets from the event target to the top of the tree is determined before the initial dispatch of the event. If modifications occur to the tree during event processing, event flow will proceed based on the initial state of the tree.

This may go some way to explaining what is happening here. The DOM tree seems to have been modified before the bubble propagates to the parent element by which time the event will target the element in the tree in that position (if any).

In this context, the element that triggered the event is removed from the tree. Rather than the event bubbling to the next element, it bubbles to the element that has now taken its position within the colleciton of elements where the initial element was, if any.

like image 119
Pineda Avatar answered Sep 23 '22 19:09

Pineda