Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

onFocus bubble in React

jsfiddle : https://jsfiddle.net/leiming/5e6rtgwd/

class Sample extends React.Component {

  onInputFocus(event) {
    console.log('react input focus')
  }

  onSpanFocus(event) {
    console.log('react span focus')
      // event.stopPropagation()
  }

  render() {
    return ( <span onFocus = {this.onSpanFocus}>
      react input: <input type="text"
      onFocus = {this.onInputFocus} />
      </span> )
  }
}

ReactDOM.render( < Sample / > ,
  document.getElementById('container')
);
<div id="container">
  <!-- This element's contents will be replaced with your component. -->
</div>

<div>
  <span onfocus="(function(){console.log('normal span')})()">
  normal input:<input type="text" onfocus="(function(){console.log('normal input focus')})()">
</span>
</div>

jsfiddle : https://jsfiddle.net/leiming/5e6rtgwd/

Using React, onFocus in <input/> will bubble which is not same as usual HTML5.

Could anyone give me the refer doc why focus bubbles with React?

like image 506
leiming Avatar asked Jan 21 '16 14:01

leiming


1 Answers

focus events do not bubble, so you're correct that the behavior in React differs from that of the DOM. The DOM has a focusin event that does bubble; here's a demonstration:

<div>
  <span onfocus="(function(){console.log('span focus')})()">
    onfocus: <input type="text"
              onfocus="(function(){console.log('input focus')})()">
  </span>
</div>

<div>
  <span onfocusin="(function(){console.log('span focusin')})()">
    onfocusin: <input type="text" 
                onfocusin="(function(){console.log('input focusin')})()">
  </span>
</div>

Looking through the React source code, it seems this was intentional; the code checks for whether or not the browser supports the focus event with capturing, and implements it via the focus event with ReactEventListener.trapCapturedEvent instead of ReactEventListener.trapBubbledEvent. This is necessary because React implements its synthetic event system using event delegation, and so needs to use either capturing or bubbling for all its event handling. The article linked to in the comment explains how this works:

The problem is that these events do not bubble up. A focus or blur event on a link fires only on the link itself, and not on any ancestor element of the link.

This is an ancient rule. A few events, most notably focus, blur, and change, do not bubble up the document tree. The exact reasons for this have been lost in the mist of history, but part of the cause is that these events just don't make sense on some elements. The user cannot focus on or change a random paragraph in any way, and therefore these events are just not available on these HTML elements. In addition, they do not bubble up.

...

Except when you use event capturing.

...

One of the most curious conclusions of my event research is that when you define event handlers in the capturing phase the browser executes any and all event handlers set on ancestors of the event target whether the given event makes sense on these elements or not.

It seems pretty likely that the React team decided to simply make the event always bubble (which, to be honest, is what I expected from the DOM spec as well until I read your question). The browser implementations don't seem to be consistent; one issue comment mentions that focus events bubble in Firefox, but I was not able to reproduce that on a recent version. However, using an onfocusin attribute or using addEventListener("focusin", ...) also didn't work in FF. So it's possible that this was simply an attempt at normalizing the events across browsers.

All that said, it does seem there is perhaps a bug where the .bubbles property on a SyntheticFocusEvent is false instead of true.

like image 157
Michelle Tilley Avatar answered Oct 12 '22 12:10

Michelle Tilley