事件处理
- React 的事件命名采用驼峰命名
- 处理事件的响应函数要以对象形式赋值给事件属性
React 事件是合成事件,并不是原生 DOM 事件。在 React 事件中必须显式调用事件对象的 preventDefault 方法来阻止事件的默认行为。
在 React 组件中处理事件最容易出错的是事件处理函数中 this 指向问题,因为 ES6 Class 不会为方法自动绑定到当前对象。
- 使用箭头函数
箭头函数的 this 指向的是函数定义时的对象,可保证 this 总是指向当前组件的实例对象。 直接在 render 方法为元素事件定义事件处理函数,最大问题是每次 render 调用时都会重新创建一个新的事件处理函数,带来额外的性能开销,组件所处层级越低,开销就越大
jsx
class Child extends Component {
handleClick(e) {
console.log(e.target);
}
render() {
return (
<div>
<button onClick={e => this.handleClick(e)} />
</div>
);
}
}- 使用组件方法
直接将组件的方法赋值给元素的事件属性,同时在类的构造函数中,将这个方法的 this 绑定当当前对象
jsx
class Child extends Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
console.log(e.target);
}
render() {
return (
<div>
<button onClick={this.handleClick(e)} />
</div>
);
}
}好处是每次 render 不会重新创建一个回调函数,没有额外的性能损失。但模版较为繁琐,还有下一种改良:
jsx
class Child extends Component {
handleClick(e) {
console.log(e.target);
}
render() {
return (
<div>
<button onClick={this.handleClick.bind(this)} />
</div>
);
}
}使用 bind 会创建一个新函数,因此该写法毅然存在每次 render 都会创建一个新函数问题
3. 属性初始化语法 property initializer syntax
使用 ES7 的 property initializers 会自动为 class 中定义的方法绑定 this:
jsx
class Child extends Component {
constructor(props) {
super(props);
this.state = { num: 0 };
}
// ES7的属性初始化方法,实际上也是使用了箭头函数
handleClick = e => {
const num = ++this.state.num;
this.setState({
num,
});
};
render() {
return (
<div>
<p>{this.state.num}</p>
<button onClick={this.handleClick}>click</button>
</div>
);
}
}这种方式既不需要在构造函数中手动绑定 this,也不需要担心组件重复渲染导致的函数重复创建问题。
