React组件中this指向问题

1,402 阅读2分钟

概要

在初次使用React时,经常会遇到this丢失的问题。下面总结几种React中绑定this的方法。

首先看下面的代码:

class Demo extends Component{
    constructor(props){
        super(props)
    }
    handleClick(){
        console.log('this', this)
    }
    render(){
        return (
            <div>
                <button onClick={this.handleClick}>点我</button>
            </div>
        )
    }
}
ReactDOM.render(<Demo/>, document.getElementById('test'))

如果之前是使用Vue开发的话,很容易写成这样,但是在react中,这样写,在执行的时候我们就会找不到this的引用。 我们首先要了解,我们在类中定义的handleClickrender方式是定义在类的原型上了。只用类的实例对象才可以调用,且函数内部的this指向实例本身。 在ReactDOM.render()执行的时候,会帮我们new一个实例对象,并调用render方法,所以在render方法内部的this指向实例自身。但是<button onClick={this.handleClick}>点我</button>这里绑定的事件处理函数为this.handleClick方法的引用。但是当我们点击的时候,handleClick的执行上下文为Window,由于jsxbabel编译后会开启严格模式。所以this指向变为undefined

1. 在构造函数中使用bind改变this的指向

class Demo extends Component{
    constructor(props){
        super(props)
        // 该方法会定义在实例对象上。
        this.handleClick = this.handleClick.bind(this)
    }
    handleClick(){
        console.log('this', this)
    }
    render(){
        return (
            <div>
                <button onClick={this.handleClick}>点我</button>
            </div>
        )
    }
}
ReactDOM.render(<Demo/>, document.getElementById('test'))

这种处理方案是我们在constructor中为每一个实例添加一个方法且this绑定为自身。 此时onClick绑定的处理函数,就不是实例原型链上的函数了,而是在constructor中为实例自身添加的方法。

我们来看下面的代码

class Demo extends Component{

    handleClick(){
        console.log('this', this)
    }
    render(){
        return (
            <div>
                <button onClick={this.handleClick(e)}>点我</button>
            </div>
        )
    }
}
ReactDOM.render(<Demo/>, document.getElementById('test'))

假如我们需要传递参数,我们可能会发现,事件并没有绑定成功。 我们仔细看,就会发现,这里我们将handleClick方法的返回值undefined绑定为onClick的处理函数。(与Vue的模板解析不同,这里是按js的语法) 我们可以使用下面这种方案。

2. 使用箭头函数绑定事件

class Demo extends Component{

    handleClick(){
        console.log('this', this)
    }
    render(){
        return (
            <div>
                <button onClick={(e) => this.handleClick(e)}>点我</button>
            </div>
        )
    }
}
ReactDOM.render(<Demo/>, document.getElementById('test'))

我们知道,render函数的this指向为实例自身,所以,我们可以直接在绑定的时候使用箭头函数,此时handleClick的执行上下文为箭头函数定义时的作用域。

3. 使用箭头函数定义实例方法

class Demo extends Component{

    // 该方法定义在实例对象,且执行上下文为实例自身
    handleClick = ()=>{
        console.log('this', this)
    }
    render(){
        return (
            <div>
                <button onClick={this.handleClick}>点我</button>
            </div>
        )
    }
}
ReactDOM.render(<Demo/>, document.getElementById('test'))

这种方案是直接将方法定义在自身上,且通过箭头函数将this指向实例自身。