【React整理系列】事件处理

【React整理系列】事件处理

一、React事件命名

不同于Vue,React的事件处理机制更加接近于原生事件的写法、 对于事件类型的指定,基本上是采用原生的写法(但是具体事件回调函数的指定有所不同):

1
2
<button onClick={activateLasers}>  Activate Lasers
</button>

即使用on+大写事件类型的形式

二、React事件参数:event对象

React中会默认传入event对象,这个event对象遵循W3C规范(也就是原生类似)

三、React阻止html元素的默认行为

在原生JavaScript中,如果要阻止元素的默认行为(比如说点击a标签默认打开链接),是在回调函数的最后 ```return false``` 但是在React,无法使用此方法,必须调用event对象中的 ```preventDefault```方法 比如:

1
2
3
4
5
6
7
8
9
10
11
function ActionLink() {
// 使用闭包指定对应回调函数
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}> Click me
</a>
);
}
四、在class组件和function组件中指定处理函数的通常格式
  • 在class组件中,我们通常将回调函数作为class对象的成员函数:

比如官方文档中这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};

// 为了在回调中使用 `this`,这个绑定是必不可少的 this.handleClick = this.handleClick.bind(this); }

handleClick() {
this.setState(state => (
{
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}

ReactDOM.render(
<Toggle />,
document.getElementById('root')
);

需要注意的有如下几点:

  1. 所有的handleClick,在外面使用的时候都必须是以this.handleClick的形式进行调用,表示调用的handleClick是当前class的成员函数.
  2. 由于JavaScript的回调函数机制,class定义的回调方法,在回调的时候,是不绑定this的(也就是说,回调的时候的this,是undefinded),关于这点,我们可以试试添加以下打印函数进行尝试:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class Link extends React.Component {
    constructor(props) {
    super(props);
    // 不给回调函数绑定this
    // this.handleClick = this.handleClick.bind(this);
    }
    handleClick(event) {
    //回调时候返回值应该是undefinded
    console.log("不绑定this,进行回调函数的时候:")
    console.log(this);
    // console.log(event);
    event.preventDefault();
    alert("clicked a ");
    };
    render() {
    // 非回调的时候
    console.log("非回调,在类中:")
    console.log(this);
    return (
    <div>
    <a href="xgpax.top" onClick={this.handleClick}>aaaa</a>
    </div>
    );
    }
    }
    ReactDOM.render(<Link />, document.getElementById("app"));

​ 显示结果: ​ ​ 很明显,我们可以看到回调函数中的this指向为undefined,所以我们需要给回调函数指定this,而这个指定方法,就是function.bind()方法(指定bind这种方法,其实不推荐使用,下文的推荐也只是一种相对而言)。 ​ 有两种指定方法:

1
1. 在调用时指定(不推荐)
1
<a href="xgpax.top" onClick={this.handleClick.bind(this)}>aaaa</a>
  1. 在constructor时指定(推荐)
1
2
3
4
5
constructor(props) {
super(props);
// 给回调函数绑定this
this.handleClick = this.handleClick.bind(this);
}

而现代化的写法,我们在第五点中讲(由于react hooks,class组件也不是很常用了)

  • 函数式组件的事件绑定机制:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 函数式事件处理
function Link() {
let test = 1;
function handleClick(event) {
console.log(event);
// 尝试打印test 证明可以使用闭包外的变量
console.log(test); // 1 打印成功
// 用来阻止默认事件的触发
event.preventDefault();
alert("clicked a!")
};
return (
<div>
<a href="xgpax.top" onClick={handleClick}>aaaa</a>
</div>
);
}

在这里需要看到的是,函数内部没有this指针,所以没有上述困扰(由于react hooks,函数式逐渐已经成为主流) 我们采用闭包的方法来定义回调函数,由于闭包的变量机制,也就不会出现变量指向问题。

五、class组件使用ES6的箭头函数来绑定事件:

使用 bind 很麻烦,我们可以利用箭头函数与上层共享this的方法来解决,这里有两种方式可以解决:

  1. 在定义事件的回调函数的时候,使用箭头函数,然后在箭头函数内部定义要执行的方法(可以指定自己需要指定的参数)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class LoggingButton extends React.Component {
    handleClick() {
    console.log('this is:', this);
    }

    render() {
    // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    return (
    <button onClick={() => this.handleClick()}> Click me
    </button>
    );
    }
    }
  2. 将回调函数修改为箭头函数的形式,用 ```变量名=()=>{}``` 的形式进行定义(create-react-app默认使用这种形式,主流)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class LoggingButton extends React.Component {
    // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    handleClick = () => {
    console.log('this is:', this);
    }
    render() {
    return (
    <button onClick={this.handleClick}>
    Click me
    </button>
    );
    }
    }
六、react回调函数事件的传参

显然,默认的event事件无法解决所需要的所有情景,而使用类似小程序中data-set的形式又不够现代,且繁琐。 我们有如下指定方式:

  1. 还是利用es6箭头函数语法
    1
    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
  2. 利用bind进行传参
    1
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。