View on GitHub

Cycle263 Blog

Stay hungry, stay foolish.

react合成事件

React自己实现了一套高效的事件注册,存储,分发和重用逻辑,在DOM事件体系基础上做了很大改进,减少了内存消耗,简化了事件逻辑,并最大化的解决了IE等浏览器的不兼容问题。React并不是将click事件直接绑定在dom上面,而是采用事件冒泡的形式冒泡到document上面,然后React将事件封装给正式的函数处理运行和处理。react 默认事件代理的方式,实际上没有任何冒泡的过程,是程序自己模拟冒泡的操作。

  class ExampleApplication extends Component {
    constructor() {
        super(arguments);
    }
    componentDidMount() {
        this.parent.addEventListener('click', (e) => {
          console.log('dom parent');
        });
        this.child.addEventListener('click', (e) => {
          console.log('dom child');
        });
        document.addEventListener('click', (e) => {
          console.log('document');
        });
    }
    childClick = () => {  
        console.log('react child');
    }
    parentClick = () => {  
        console.log('react parent');
    }
    render() {
      <div onClick={this.parentClick} ref={ref => this.parent = ref}>
        <div onClick={this.childClick} ref={ref => this.child = ref}>
        </div>
      </div>
    }
  }
  // dom child
  // dom parent
  // react child
  // react parent
  // document

合成事件示意图

常见问题

Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property target on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist(). See https://fb.me/react-event-poo... for more information.

为何要手动绑定this?

react对生命周期的钩子函数都进行this绑定,但是对开发者自定义的函数并没有绑定this指向。其实,在react@0.13版本之前, React createClass这个API是默认绑定this的,绝大部分情况很安逸,但是开发者缺失去了对context的控制权。

// dispatchEvent调用了invokeGuardedCallback方法
function invokeGuardedCallback(name, func, a) {
  try {
    func(a);  // 回调函数是直接调用,并没有指定组件
  } catch (x) {
    if (caughtError === null) {
      caughtError = x;
    }
  }
}

参考资料

react为何不像vue一样自动绑定所有函数的this指向?