在 React 底层,主要对合成事件做了两件事:事件委派和自动绑定。
1. 事件委派
在使用 React 事件前,一定要熟悉它的事件代理机制。它并不会把事件处理函数直接绑定到 真实的节点上,而是把所有事件绑定到结构的最外层,使用一个统一的事件监听器,这个事件监 听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。当组件挂载或卸载时,只是 在这个统一的事件监听器上插入或删除一些对象;当事件发生时,首先被这个统一的事件监听器 处理,然后在映射里找到真正的事件处理函数并调用。这样做简化了事件处理和回收机制,效率 也有很大提升。
2. 自动绑定
在 React 组件中,每个方法的上下文都会指向该组件的实例,即自动绑定 this 为当前组件。 而且 React 还会对这种引用进行缓存,以达到 CPU 和内存的最优化。在使用 ES6 classes 或者纯 函数时,这种自动绑定就不复存在了,我们需要手动实现 this 的绑定。
现在我们来看几种绑定的方法:
- bind 方法。这个方法可以帮助我们绑定事件处理器内的 this ,并可以向事件处理器中传 5 递参数,比如:
import React, { Component } from 'react'; class App extends Component { handleClick(e, arg) { console.log(e, arg); } render() { // 通过bind方法实现,可以传递参数 return <button onClick={this.handleClick.bind(this, 'test')}>Test</button>; } }
如果方法只绑定,不传参,那 stage 0 草案中提供了一个便捷的方案1——双冒号语法,其作 用与 this.handleClick.bind(this) 一致,并且 Babel 已经实现了该提案。比如:
import React, { Component } from 'react’; class App extends Component { handleClick(e) { console.log(e); } render() { return <button onClick={::this.handleClick}>Test</button>; } }
- 构造器内声明。在组件的构造器内完成了 this 的绑定,这种绑定方式的好处在于仅需要 进行一次绑定,而不需要每次调用事件监听器时去执行绑定操作:
import React, { Component } from 'react'; class App extends Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(e) { console.log(e); } render() { return <button onClick={this.handleClick}>Test</button>; } }
- 箭头函数。箭头函数不仅是函数的“语法糖”,它还自动绑定了定义此函数作用域的 this, 因此我们不需要再对它使用 bind 方法。比如,以下方式就能运行:
import React, { Component } from 'react'; class App extends Component { const handleClick = (e) => { console.log(e); }; render() { return <button onClick={this.handleClick}>Test</button>; } } 或 import React, { Component } from 'react'; class App extends Component { handleClick(e) { console.log(e); } render() { return <button onClick={() => this.handleClick()}>Test</button> }}
使用上述几种方式,都能够实现在类定义的组件中绑定 this 上下文的效果。
(原文出自《深入react技术栈》)
(原文出自《深入react技术栈》)