一个简单的React事件绑定

需要事件绑定的原因

首先说明一下,React生成出来的事件,里面的this并不是指向自身的,这是Javascript语法的规定,是不可避免的。

比如<button onClick={this.plus}>plus</button>中,plus上的this其实是绑在了window上的,也就是事件响应时的上下文,并不是当前的组件实例。说简单点,就是当触发该事件时,是在浏览器的总的一个环境里的,所以这时事件里如果用到this的话,this指向的其实是window。

但是这样会使得事件的使用和处理变得相当麻烦,所以这时就需要将事件内的this指针转移到事件的作用域上。

简单看一下bind()函数

调用 bind() 会创建一个新的函数,当这个新函数被调用时,函数内部的this会被置为参数提供的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var example = {
value: 114514,
getValue: function() {
return this.value; //这里使用了this
}
}

var unbindThis = example.getvalue;
console.log(unbindThis()); // 调用的对象是window,所以里面的this.value => window.value
// output: undefined

var bindThis = unbindThis.bind(example);
console.log(bindThis()); // 但是bind之后,会将this的值置为example提供的值
// output: 114514

选择绑定this的方法

首先需要了解一下:
DOM是浏览器生成的文档树接口,该接口使用JS实现的,但是浏览器会将这两者分开,所以每次用JS调用DOM时都会有不小的开销。同时 bind() 会创建一个重新绑定this的函数实例,相当于是将原来的函数进行了一次拷贝,这就会产生巨大的浪费。React想要把系统的方法关联到DOM上,将JS嵌入组件中,从而降低耦合。所以这时就需要根据情况选择一种最优的方式将this绑定。

bind()

  • 每次重新渲染时都会重新生成一个函数实例,数量多时会浪费内存。
  • 如果是将该绑定方法作为组件的props传给子组件,那子组件会认为这时生成的新函数实例是不同的参数,会导致重新渲染。
1
<button onClick={this.handleEdit.bind(this, param)}>编辑</button>

箭头函数调用

  • 效果同bind,也会导致重新绑定
1
<button onClick={(param) => this.handleEdit(param)}>编辑</button>

在构造器中使用bind声明

  • 官方推荐
  • 性能最好
  • 事件只会生成一个
1
2
3
4
5
6
7
8
9
10
class Login extends React.Component {
constructor(props) {
super(props);
this.login = this.login.bind(this); //在这里绑定了事件
this.check = this.check.bind(this);
this.state = {
userName: 'admin',
passWord: 'admin',
};
}

箭头函数声明

  • 推荐
  • 但是不能带参数
1
2
3
handleClick = (e) => {
console.log(e);
}

类的属性初始化

  • 不是ES标准,可能有兼容性问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
}

toggleHander = () => {
this.setState(preState => ({
isToggleOn: !preState.isToggleOn
}));
}

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

一个在构造函数中使用 bind() 绑定的例子

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>

<script
src="https://unpkg.com/react@16/umd/react.development.js"
crossorigin
></script>
<script
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"
crossorigin
></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class Login extends React.Component {
constructor(props) {
super(props);
this.login = this.login.bind(this);
this.check = this.check.bind(this);
this.state = {
userName: 'admin',
passWord: 'admin',
};
}
login() {
if (
this.refs.user.value === this.state.userName &&
this.refs.pwd.value === this.state.passWord
) {
alert('success');
} else {
alert('failed');
}
}
check() {
if (this.refs.user.value.length > 10)
alert('more than 10 characters, checkout again.');
}
render() {
var loginStyle = {
width: 400,
height: 250,
background: '#FFF',
margin: '200px auto',
position: 'relative',
};
var hStyle = {
position: 'absolute',
left: 95,
top: -40,
padding: 0,
margin: 50,
};
var pStyle = {
textAlign: 'center',
};
var userStyle = {
width: 200,
height: 30,
border: 'solid #ccc 1px',
borderRadius: 3,
paddingLeft: 32,
marginTop: 50,
};
var pwdStyle = {
width: 200,
height: 30,
border: 'solid #ccc 1px',
borderRadius: 3,
paddingLeft: 32,
marginTop: 5,
};
var buttonStyle = {
width: 232,
height: 30,
background: '#E9E9E9',
border: 'solid #ccc 1px',
borderRadius: 3,
textAlign: 'center',
};
return (
<div style={loginStyle}>
<h1 style={hStyle}>LOGIN</h1>
<div>
<p style={pStyle}>
<input
type="text"
style={userStyle}
placeholder="USERNAME"
ref="user"
onChange={this.check}
/>
</p>
<p style={pStyle}>
<input
type="password"
style={pwdStyle}
placeholder="PASSWORD"
ref="pwd"
/>
</p>
<p style={pStyle}>
<button style={buttonStyle} onClick={this.login}>
LOGIN!
</button>
</p>
</div>
</div>
);
}
}
ReactDOM.render(<Login />, document.getElementById('root'));
</script>
</body>
</html>

参考

作者

Jhuoer Yen

发布于

2021-11-01

更新于

2023-09-18

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×