jsx是以回调的形式绑定事件
例子:
<button onClick={ this.showData }>点击</button>
jsx绑定事件的时候是以回调的形式进行绑定。
怎么理解,就是当jsx解析的时候,会把{}里的内容作为日后click事件触发时执行的回调函数。
如果我们这样写onClick={ this.showData() }
,在jsx解析过程就直接执行了,会报错。
jsx绑定函数时使用匿名函数会有什么副作用
例如:
fn = () => {}
render() {
return <div onClick={()=>{this.fn}}>
}
组件每次更新都不会使用缓存优化,每次都要定义一次匿名函数,并且执行。会给性能上带来一定量的损耗。
react事件和dom事件的区别
react dom上写的事件不是真实的事件,是叫做“合成事件“的东西来模拟的,通过捕获冒泡等机制把所有”事件“统一挂到react的root节点去实现事件本身。
这种合成事件,因为不依赖于具体的某项dom,所以可以做到跨平台(我猜应该是类似react的root节点一样,通过一个类似的聚合的东西去实现)。
总结:
- 为了更好的兼容性,跨平台;
- 事件是通过事件委托方式处理的(委托给组件最外层的元素) ,为了的高效;
- 事件会默认传递一个重写的参数
event
,可以通过target
属性拿到绑定方法的对应dom对象等等;
关于函数this的指向
首先我们知道,在es6中class实例化后的对象是可以通过执行函数,通过函数的this拿到class上定义的属性的:
class Person {
constructor(name, age) {
this.name = name; // 意思是给类添加一个name属性,值为实例化后传进来的name
this.age = age;
}
showName() {
alert(this.name);
}
}
let p1 = new Person("xiaoqiang", 123); // 实例化一个类
p1.showName(); // 正常拿到name
但是我们在jsx中绑定事件后,this的指向问题就出现了。
import React, { Component } from 'react'
export default class App extends Component {
constructor() {
super()
this.str = '可以拿到吗'
}
state = {
a: '1',
b: '1'
}
noGoodThis() {
console.log("this", this); // undefined
}
render() {
return (
<div onClick={this.noGoodThis}>点击</div>
)
}
}
这是为什么呢?
- 我们在jsx绑定的类中的方法,并不是像class类的实例去调用的,具体是怎么样调用的是react处理的。然后react并不会帮我们把这个函数内的this指向类实例,所以当函数通过this去获取类实例的一些方法或属性就会有问题。
- 类中的自定义方法默认开启了局部的严格模式,所以函数中的this为
undefined
。
为了让内部的this指向正确,比较蠢的办法是,手动把函数的this指向实例对象。
export default class App extends Component {
constructor() { // 构造器只会调用一次
super()
this.str = '可以拿到吗'
this.noGoodThis = this.noGoodThis.bind(this); // 改变noGoodThis函数的指向
}
noGoodThis() { // 会被放在Acomponent的原型对象上,供实例使用
console.log("this", this); // 正常拿到
}
render() { //render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
return (
<div onClick={this.noGoodThis}>点击</div>
)
}
}
当然这样去改写this很麻烦,用赋值语句的形式+箭头函数的方式就很方便。
使用箭头函数是为了onClick外部调用这个方法的时候,能通过this得到实例对象,箭头函数this指向自身环境;
export default class App extends Component {
constructor() {
super()
this.str = '可以拿到吗'
}
noGoodThis = () => { // 这样this指向这个环境,就是实例化对象
console.log("this", this);
}
render() {
return (
<div onClick={this.noGoodThis}>点击</div>
)
}
}
所以,以后在写类式组件中定义一个函数,要以箭头函数赋值的形式写。
如何阻止默认事件
在vue中模板会给我们提供一些修饰符,但在react需要使用"类似"原生的方法来阻止默认事件
export default class App extends Component {
fn = (event) => {
event.preventDefault() // 阻止默认事件
}
}
它这个阻止默认事件的api应该是重写的,做了浏览器兼容处理。
好像在原生事件中阻止默认冒泡行为,也会阻止react合成事件的传播。
什么是高阶函数
满足以下其中一个条件的就是高阶函数:
- 函数接收的参数是一个函数;
- 函数返回的是个函数;
原生的高阶函数有:Promise、setTimeOut、很多数据类型的api等等;
函数柯里化(接收多个参数)
柯里化其实就是一个函数调用后,内部的返回函数对每个函数的入参进行统一处理的函数类型。函数柯里化可以解决jsx绑定函数时怎么传入多个参数问题:
export default class App extends Component {
// ...
fn = (xxx) => { // 这样就可以在jsx中以this.fn('xxx') 的参数的形式调用函数
return (event)=>{ // 这个返回的函数变成了真正的回调,event为默认事件参数
// 内部可对入参进行统一处理
}
}
}
一般不用柯里化的写法,可读性不高,用箭头函数代替:
<div onClick={ event => this.fn('a', event) }>点我</div>
啥?看不懂?其实就是{}里放了个函数,可以把event => this.fn('username', event)
整体成是一个Fn,onChange={ Fn }
,然后react回调执行,就执行里面的this.fn('username', event)
了。
这样函数就能接到多个参数:
export default class App extends Component {
//...
fn = (str, event)=>{
console.log(str, event.target.value)
}
}