目录
- 1. 事件绑定
- 1.1 函数组件
- 1.2 类组件
- 2. 合成事件
- 3. 事件传参的3种不同写法
- 4. this 指向问题
1. 事件绑定
React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:
React 事件的命名采用小驼峰式,而不是纯小写。
onClick
=> onChange
使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
onClick={this.fn}
// 绑定实现方法一定要用 {函数或方法};注意函数或方法不能用小括号
类组件与函数组件绑定事件是差不多的,只是在类组件中绑定事件函数的时候需要用到 this,代表指向当前的类的引用,在函数中不需要调用 this
1.1 函数组件
import React, { Component } from 'react'
// 函数组件中没有this指向问题
const App = () => {
let num = 1
const clickFn = () => {
console.log(num++)
}
// const clickFn = () => () => {
// console.log(num++)
// }
return (
<div>
{/* 普通的值,它不具备响应式,所以你修改数据后,视图是不会更新的 */}
<h3>App组件 -- {num}</h3>
{/* 绑定点击事件 */}
{/* 一般情况下,绑定的实现方法是不会加小括号,如果要加小括号,则定义绑定方法时,一定要返回一函数 */}
<button onClick={clickFn}>++++</button>
{/* <button onClick={clickFn()}>++++</button> */}
</div>
)
}
export default App
1.2 类组件
import React, { Component } from 'react'
class App extends Component {
num = 100
todos = []
// 建议使用箭头函数定义成员属性
addNum = () => {
// 同步修改成员属性中的数据,但是视图不更新
this.num++
// 类组件中提供一个方法,可以强制让视图更新
this.forceUpdate()
}
// react事件,在没有写小括号的时候会主动的把event对象传给你
onEnter = evt => {
if (evt.keyCode === 13) {
this.todos.push({
id: Date.now(),
title: evt.target.value.trim(),
done: false
})
evt.target.value = ''
// 通知视图更新
this.forceUpdate()
}
}
render() {
return (
<div>
<h3>{this.num}</h3>
<ul>
{this.todos.map(item => (
<li key={item.id}>{item.title}</li>
))}
</ul>
{/*
类组件中绑定方法,有this指向问题
*/}
<button onClick={this.addNum}>++++</button>
<input type="text" onKeyUp={this.onEnter} />
</div>
)
}
}
export default App
2. 合成事件
概述:
在原生 Dom 事件( html 中),假如我们给 button 按钮绑定点击事件,是绑定在 button 上去的。而这种情况在 React 中,不会在 button 上绑定事件,React 会将 Dom 中的事件进行收集,然后将事件委托到容器中(id=root,即挂载点)。
在 React16 及之前,React 将所有的事件都委托到 document 当中去,而在 React17 及之后,React 将所有的事件都委托到挂载点中去了。
为什么出现这个技术?
- 性能优化:使用事件代理统一接收原生事件的触发,从而可以使得真实 DOM 上不用绑定事件。React 挟持事件触发可以知道用户触发了什么事件,是通过什么原生事件调用的真实事件。这样可以通过对原生事件的优先级定义进而确定真实事件的优先级,再进而可以确定真实事件内触发的更新是什么优先级,最终可以决定对应的更新应该在什么时机更新。
- 分层设计:解决跨平台问题,抹平浏览器差异和平台差异。
3. 事件传参的3种不同写法
import React, { Component } from 'react';
class App extends Component {
// 在react中事件对象,它是通过事件参数传给方法的
// 参数空着,会默认绑定事件
fn = () => {
console.log('fn')
}
// 又想传参,又想触发事件得这么写,evt会自动映射过来,注意最后一个箭头前只能是 evt 对象
fn1 = num => evt => {
console.log(num, evt);
}
// 这种写法是可以随意变更 evt 对象传参过来的位置
fn2 = (num, evt) => {
console.log(num, evt);
}
render() {
return (
<div>
{/* onClick={ 注意:花括号里是函数的表达式,而不是函数的调用 } */}
<button onClick={this.fn}>绑定点击事件</button>
<button onClick={this.fn1(100)}>绑定点击事件</button>
<button onClick={evt => this.fn2(200, evt)}>绑定点击事件</button>
</div>
);
}
}
export default App;
4. this 指向问题
在JSX事件函数方法中的 this,默认不会绑定 this 指向。如果你忘记绑定,当你调用这方法的时候,this 的值为 undefined。所以使用时一定要绑定好 this 的指向。
this 指向针对的是类组件,函数组件没有 this 问题,因为函数没有 this 。
利用 bind 函数绑定 this 指向:
import React, { Component } from 'react';
class App extends Component {
num = 100
// 类的构造函数,它只执行1次,在初始化
// constructor(props) {
// super(props);
// // 在构建函数中统一的把事件方法this绑定好
// this.addNum = this.addNum.bind(this)
// }
// 在react事件绑定的类组件中,默认情况this指向会可能存在指向问题 undefined
// 在绑定事件中绑定this调用函数时的写法
addNum(n = 1) {
this.num += n
this.forceUpdate()
}
// 构造函数中绑定this调用函数时的写法,因为不传值第一个参数会
// addNum(evt, n = 1) {
// this.num += n
// this.forceUpdate()
// }
render() {
return (
<div>
<h3>{this.num}</h3>
{/* 在此处可以使用bind来绑定this指向(this指向 App 实例),且还可以传参数 */}
{/* 此方案在使用中,较多 */}
{/* <button onClick={this.addNum.bind(this)}>累加</button> */}
<button onClick={this.addNum.bind(this, 2)}>累加</button>
{/* 如果你这样写,又想this指向对,则一定要在构造函数中,解决好this指向 */}
{/* <button onClick={this.addNum}>累加</button> */}
</div>
);
}
}
export default App;
注意:使用 bind 绑定 this 共有两种方案,一种是调用函数时绑定,一种是在构造函数中统一绑定。
利用箭头函数解决 this 指向:
import React, { Component } from 'react';
class App extends Component {
num = 100
// 类的构造函数,它只执行1次,在初始化
// constructor(props) {
// super(props);
// // 在构建函数中统一的把事件方法this绑定好
// this.addNum = this.addNum.bind(this)
// }
// 在react事件绑定的类组件中,默认情况this指向会可能存在指向问题 undefined
// 在绑定事件中绑定this调用函数时的写法
addNum(n = 1) {
this.num += n
this.forceUpdate()
}
// 构造函数中绑定this调用函数时的写法,因为不传值第一个参数会
// addNum(evt, n = 1) {
// this.num += n
// this.forceUpdate()
// }
render() {
return (
<div>
<h3>{this.num}</h3>
{/* 在此处可以使用bind来绑定this指向(this指向 App 实例),且还可以传参数 */}
{/* 此方案在使用中,较多 */}
{/* <button onClick={this.addNum.bind(this)}>累加</button> */}
<button onClick={this.addNum.bind(this, 2)}>累加</button>
{/* 如果你这样写,又想this指向对,则一定要在构造函数中,解决好this指向 */}
{/* <button onClick={this.addNum}>累加</button> */}
</div>
);
}
}
export default App;