Event Capturing and Bubbling in React
Tags: react, javascript, webdev
Published: 2020-12-10 19:26:52

Imagine you have the following code:

```jsx
  const [counter, setCounter] = useState(0);
  return (
    <div onClick={() => setCounter((prevCounter) => prevCounter + 1)}>
      <button onClick={() => setCounter((prevCounter) => prevCounter + 1)}>
        Counter value is: {counter}
      </button>
    </div>
  );
```

That renders this button:

![Screen Shot 2020-12-10 at 10.27.49 AM](https://dev-to-uploads.s3.amazonaws.com/i/op5ua4plyv0kfdds861m.png)

What would be displayed on that button if you click it?

If you guessed "Counter value is: 1", you were **wrong**!

What we get is this:

![Screen Shot 2020-12-10 at 10.30.19 AM](https://dev-to-uploads.s3.amazonaws.com/i/kxgzxpgmi1iqlr83op5s.png)

But why? 

### Understanding Event Propagation

In our example, although we clicked on the `button`, the event handler of its `div` parent was triggered as well. That's because events don't just affect the target element that generated the event—they travel up and down through the DOM tree to reach their target. 
This is known as event propagation: a mechanism that defines how events propagate or travel through the DOM tree to arrive at its target and what happens to it afterward.

The concept of event propagation was introduced to deal with the situations in which multiple elements in the DOM hierarchy with a parent-child relationship have event handlers for the same event, such as a mouse click. Now, the question is which element's click event will be handled first when the user clicks on the inner element: the click event of the outer element, or the inner element?

Event Propagation has three phases:
1.  Capturing Phase - the event starts from the `window` down until it reaches the `event.target`. 
2.  Target Phase - the event has reached the `event.target`. The most deeply nested element that caused the event is called a target element, accessible as `event.target`.
3.  Bubbling Phase - the event bubbles up from the `event.target` element up until it reaches the `window`, meaning: when an event happens on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors. That's the reverse of what is happening in the Capturing Phase.

![hjayqa99iejfhbsujlqd](https://dev-to-uploads.s3.amazonaws.com/i/h4x9s94j81goxrc0kcnd.png)

### Event Bubbling and Capturing in React

Bubbling and capturing are both supported by React in the same way as described by the DOM spec, except for how you go about attaching handlers.

Bubbling is as straightforward as with the normal DOM API; simply attach a handler to an eventual parent of an element, and any events triggered on that element will bubble to the parent, just like in our example in the beginning.

Capturing is just as straightforward, but instead of the `onClick` prop, you have to use `onClickCapture` on your element. 

### How Do You Stop an Event from Bubbling/Capturing?

Going back to our original example, how can we make sure our counter is only incremented by 1 when we click the button?

The answer is using `stopPropagation()`
This method of the `Event` interface prevents further propagation of the current event in the capturing and bubbling phases. 
It does not, however, prevent any default behaviors from occurring. (if you want to stop those behaviors, you would need to use the `preventDefault()` method)

If we change our code to:

```jsx
  const [counter, setCounter] = useState(0);
  return (
    <div onClick={() => setCounter((prevCounter) => prevCounter + 1)}>
      <button
        onClick={(event) => {
          event.stopPropagation();
          setCounter((prevCounter) => {
            return prevCounter + 1;
          });
        }}
      >
        Counter value is: {counter}
      </button>
    </div>
```

Our counter will be incremented by 1 each time we click the button, thanks to `event.stopPropagation()` which prevents the event from bubbling up to `button`'s parent and triggering the parent's `onClick` as well.

However, be careful when stopping events from propagating, because sometimes you can’t really be sure you won’t be needing the event above in one of the element's parents, maybe for completely different things.

If this is the case, one alternative to stopping the propagation is writing your data into the event object in one handler and read it in another one, so you can pass to handlers on parents information about the processing below.

Happy coding!! :rocket: